2013-10-03 4 views
0

Я хочу использовать всплывающие подсказки, как они были предназначены. Но когда возникает ошибка, я хочу изменить их, чтобы показать сообщение об ошибке, а затем, когда ошибка исправлена, измените их.WPF создать прикрепленное свойство для всплывающих подсказок

Таким образом, я создал прикрепленное свойство для хранения всплывающей подсказки. Я назначаю всплывающую подсказку прикрепленному свойству, а затем использую стиль для копирования его в свойство всплывающей подсказки. Если есть ошибка, стиль вместо этого устанавливает подсказку в сообщение об ошибке.

Так триггеры, чтобы установить сообщение об ошибке в подсказке являются:

<Trigger Property="Validation.HasError" 
       Value="true"> 
<Setter Property="BorderBrush" 
       Value="{DynamicResource controls-errorBorderBrush}" /> 
<Setter Property="ToolTip" 
       Value="{Binding RelativeSource={x:Static RelativeSource.Self}, 
    Path=(Validation.Errors)[0].ErrorContent}" /> 
</Trigger> 

Это кажется довольно легко (и работает)

Когда фиксируется ошибка, я поставил его обратно (это Безразлично» т работы):

<Trigger Property="Validation.HasError" 
Value="false"> 
<Setter Property="ToolTip" 
    Value="{Binding Path=(wpfMisc:myCtrl.tooltipValue)}" /> 
</Trigger> 

И в файле XAML у меня есть:

<TextBox Text="this is a textbox with a myMisc based tooltip" 
Name="txtTooltip2" 
wpfMisc:myCtrl.tooltipValue="Tooltip Test tooltip" /> 

Итак, проблема, скорее всего, связана с моим прикрепленным свойством, так как кажется, что информация не сохраняется правильно. Вот этот код:

public static string GettooltipValue(DependencyObject obj) 
{ 
string value = obj.GetValue(tooltipValueProperty).ToString() ; 
value = value.trimNull() ; // extension method to insure at least an empty string 
return value ; 
} 

public static void SettooltipValue(DependencyObject obj, string value) 
{ 
obj.SetValue(tooltipValueProperty, value.trimNull()); 
} 

public static readonly DependencyProperty tooltipValueProperty = 
DependencyProperty.RegisterAttached("tooltipValue", 
typeof(string), 
typeof(myCtrl), 
new UIPropertyMetadata(string.Empty)); 

Так что я думаю, что мне нужно использовать что-то другое в UIPropertyMetaData, но не уверен, что я хотел бы использовать. Или мой подход просто ошибается?

Я хочу иметь подсказки для конкретных данных для всех полей данных.

У меня была эта работа, перемещая всплывающую подсказку в свойство тега во время ошибки, но я не хотел, чтобы он работал так, потому что я знаю, что у меня возникнут проблемы, когда какой-либо другой код захочет использовать тегом каким-то особым образом.

Кроме того, я знаю, что некоторые из кода многословен - просто побочный эффект отладки ...

И еще одно свойство зависимостей в myCtrl работает просто отлично, так что я знаю Xmlns и т.д. ссылки верный.

В дальнейших исследованиях я нашел следующее в окне вывода: Ошибка System.Windows.Data: 17: Невозможно получить значение «tooltipValue» (введите «String») из «'(введите« layoutSettingsViewModel »). BindingExpression: Путь = (0); DataItem = 'layoutSettingsViewModel' (HashCode = 46457861); целевым элементом является «TextBox» (Name = ''); target property - это «ToolTip» (тип «Object») InvalidCastException: «System.InvalidCastException: не удается лить объект типа« client.Models.layoutSettings.layoutSettingsViewModel »для ввода« System.Windows.DependencyObject ».

layoutSettingsViewModel - это представление xaml. Поэтому я считаю, что само представление каким-то образом получает значение вместо элементов управления ... Не уверен, хотя - я предполагаю, что один из вас точно знает, что это значит и почему ... Я ненавижу пытаться встать на скорость на новый язык ...

В любом случае, любая помощь и/или предложения приветствуются.

+0

вы получаете какие-либо обязательные ошибки в окне вывода, когда проверка .HasError установлен в false? и как и где вы устанавливаете wpfMisc: myCtrl.tooltipValue? Также можете ли вы поделиться элементом управления, на котором вы применяете эти триггеры? – Nitin

+0

2 вещи, которые я бы начал с: сначала попробуйте вернуть только obj.GetValue не нужно для всего остального кода, так как wpf (C#) может оптимизировать ваш вложенный код свойства, и обычно это будет реализация по умолчанию, которая, вероятно, не так (0), Во-вторых, добавьте обратный вызов для своего dp и посмотрите, действительно ли значение изменяет, когда и к чему вы, дайте мне знать, что вы придумали. –

+0

nit, у меня был код, но по какой-то причине он не показывался. Сейчас. И я тестировал с помощью простого текстового поля, хотя я хочу использовать его с любым элементом управления вводом данных. – JustMeToo

ответ

0

Я создал аналогичную функциональность, но для Button элементов управления. Я предоставил вам свой рабочий код для этого, и вам просто нужно заменить Button на любой элемент управления, который вы хотите использовать.Я должен был создать AttachedProperty для инвалидов ToolTip сообщения, а другой к «вспомнить» исходное значение:

private static readonly DependencyPropertyKey originalToolTipPropertyKey = DependencyProperty.RegisterAttachedReadOnly("OriginalToolTip", typeof(string), typeof(ButtonProperties), new FrameworkPropertyMetadata(default(string))); 

/// <summary> 
/// Contains the original Button.ToolTip value to display when the Button.IsEnabled property value is set to true. 
/// </summary> 
public static readonly DependencyProperty OriginalToolTipProperty = originalToolTipPropertyKey.DependencyProperty; 

/// <summary> 
/// Gets the value of the OriginalToolTip property. 
/// </summary> 
/// <param name="dependencyObject">The DependencyObject to return the OriginalToolTip property value from.</param> 
/// <returns>The value of the OriginalToolTip property.</returns> 
public static string GetOriginalToolTip(DependencyObject dependencyObject) 
{ 
    return (string)dependencyObject.GetValue(OriginalToolTipProperty); 
} 

/// <summary> 
/// Provides Button controls with an additional tool tip property that only displays when the Button.IsEnabled property value is set to false. 
/// </summary> 
public static DependencyProperty DisabledToolTipProperty = DependencyProperty.RegisterAttached("DisabledToolTip", typeof(string), typeof(ButtonProperties), new UIPropertyMetadata(string.Empty, OnDisabledToolTipChanged)); 

/// <summary> 
/// Gets the value of the DisabledToolTip property. 
/// </summary> 
/// <param name="dependencyObject">The DependencyObject to return the DisabledToolTip property value from.</param> 
/// <returns>The value of the DisabledToolTip property.</returns> 
public static string GetDisabledToolTip(DependencyObject dependencyObject) 
{ 
    return (string)dependencyObject.GetValue(DisabledToolTipProperty); 
} 

/// <summary> 
/// Sets the value of the DisabledToolTip property. 
/// </summary> 
/// <param name="dependencyObject">The DependencyObject to set the DisabledToolTip property value of.</param> 
/// <param name="value">The value to be assigned to the DisabledToolTip property.</param> 
public static void SetDisabledToolTip(DependencyObject dependencyObject, string value) 
{ 
    dependencyObject.SetValue(DisabledToolTipProperty, value); 
} 

/// <summary> 
/// Adds ro removes event handlers to the Button control that updates the Button.ToolTip value to the DisabledToolTip property value when the Button.IsEnabled property value is set to false. 
/// </summary> 
/// <param name="dependencyObject">The Button object.</param> 
/// <param name="e">The DependencyPropertyChangedEventArgs object containing event specific information.</param> 
public static void OnDisabledToolTipChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) 
{ 
    Button button = dependencyObject as Button; 
    if (button != null && e.OldValue != e.NewValue) button.IsEnabledChanged += Button_IsEnabledChanged; 
    else if (e.OldValue != null && e.NewValue == null) button.IsEnabledChanged -= Button_IsEnabledChanged; 
} 

private static void Button_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e) 
{ 
    Button button = sender as Button; 
    if (GetOriginalToolTip(button) == null) button.SetValue(originalToolTipPropertyKey, button.ToolTip.ToString()); 
    button.ToolTip = (bool)e.NewValue ? GetOriginalToolTip(button) : GetDisabledToolTip(button); 
} 

Он используется так:

<Button ToolTip="Normal ToolTip text to display" 
    Attached:ButtonProperties.DisabledToolTip="Text to automatically display when 
    Button is disabled"> 
+0

Я предполагаю, что вы имели в виду, что строка 156 должна быть - = вместо + = (или я пропущу что-то очевидное?) – JustMeToo

+0

Это было бы вторым, если в OnDisabledToolTipChanged (так как я переформатировал код, строки #s не совпадают). Кроме того, я не могу получить всплывающую подсказку, чтобы показать, когда кнопка отключена - даже если я просто использую регулярную подсказку. Я что-то пропустил? – JustMeToo

+0

Ха да, хорошее место о '- =', спасибо! Он должен работать, но вы должны установить как регулярные 'ToolTip', так и * свойства DisabledToolTip' ... он работает для меня. Поместите контрольную точку в обработчик 'Button_IsEnabledChanged', чтобы узнать, вызвана ли она ... если это не так, у вас могут возникнуть проблемы с вашим классом' AttachedProperty'. – Sheridan

0

Для тех, кто заботится, здесь является основным логика - построена на коде, который разделяет Шеридан. Я знаю, что это можно сделать более сжатым и т. Д. Но это облегчает работу нового разработчика WPF, чтобы увидеть, как все работает.

Вот стиль XAML - который может быть использован для любого элемента управления, который поддерживает всплывающую подсказку и данные:

<Style TargetType="TextBox"> 
<Style.Triggers> 
    <Trigger Property="Validation.HasError" 
         Value="true"> 
     <!-- We have an error, set the ErrorToolTip attached property to 
     the error. When the error is no more, it is automatically set 
     back to the original value (blank) so no need for a 2nd trigger --> 
     <Setter Property="wpfMisc:myCtrl.ErrorToolTip" 
         Value="{Binding RelativeSource={x:Static RelativeSource.Self}, 
     Path=(Validation.Errors)[0].ErrorContent}" /> 

    </Trigger> 

</Style.Triggers> 
</Style> 

А вот код, который может быть добавлен к классу (с помощью myCtrl здесь), что имеет место свойства зависимостей/атрибуты:

/// <summary> 
/// Holds the default Tooltip value. OnMyToolTipChanged used to set ToolTip 
/// </summary> 
public static DependencyProperty MyToolTipProperty = DependencyProperty.RegisterAttached("MyToolTip", typeof(string), typeof(myCtrl), new UIPropertyMetadata(string.Empty, OnMyToolTipChanged)); 

/// <summary> 
/// Gets the value of the MyToolTip property. 
/// </summary> 
/// <param name="dependencyObject">The DependencyObject to return the MyToolTip property value from.</param> 
/// <returns>The value of the MyToolTip property.</returns> 
public static string GetMyToolTip(DependencyObject dependencyObject) 
{ 
    return (string)dependencyObject.GetValue(MyToolTipProperty); 
} 

/// <summary> 
/// Sets the value of the MyToolTip property. 
/// </summary> 
/// <param name="dependencyObject">The DependencyObject to set the MyToolTip property value of</param> 
/// <param name="value">The value to be assigned to the MyToolTip property.</param> 
public static void SetMyToolTip(DependencyObject dependencyObject, string value) 
{ 
    dependencyObject.SetValue(MyToolTipProperty, value); 
} 

/// <summary> 
/// Initially blank, set by style when an error occures (or goes away). Uses OnErrorToolTipChanged to update ToolTip. 
/// </summary> 
public static DependencyProperty ErrorToolTipProperty = DependencyProperty.RegisterAttached("ErrorToolTip", typeof(string), typeof(myCtrl), new UIPropertyMetadata(string.Empty, OnErrorToolTipChanged)); 

/// <summary> 
/// Gets the value of the ErrorToolTip property. 
/// </summary> 
/// <param name="dependencyObject">The DependencyObject to return the ErrorToolTip property value from</param> 
/// <returns>The value of the ErrorToolTip property.</returns> 
public static string GetErrorToolTip(DependencyObject dependencyObject) 
{ 
    return (string)dependencyObject.GetValue(ErrorToolTipProperty); 
} 

/// <summary> 
/// Sets the value of the ErrorToolTip property. 
/// </summary> 
/// <param name="dependencyObject">The DependencyObject to set the ErrorToolTip property value of</param> 
/// <param name="value">The value to be assigned to the ErrorToolTip property.</param> 
public static void SetErrorToolTip(DependencyObject dependencyObject, string value) 
{ 
    dependencyObject.SetValue(ErrorToolTipProperty, value); 
} 

/// <summary> 
/// If an Error Tooltip is supplied, sets the ToolTip to that value, otherwise, resets it back to MyToolTipProperty 
/// </summary> 
/// <param name="dependencyObject">The control with the tooltip</param> 
/// <param name="e">The DependencyPropertyChangedEventArgs object containing event specific information.</param> 
public static void OnErrorToolTipChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) 
{ 
    if (dependencyObject is TextBox) 
    { 
     var txtControl = dependencyObject as TextBox; 
     if (e.NewValue == null || e.NewValue.ToString() == string.Empty) 
     { 
      // No tooltip, reset to the original value 
      txtControl.ToolTip = (string)dependencyObject.GetValue(MyToolTipProperty); 
     } 
     else 
     { 
      // Use the error tooltip 
      txtControl.ToolTip = e.NewValue; 
     } 
    } 
} 

/// <summary> 
/// This should only be called when the value is first assigned to the control. 
/// </summary> 
/// <param name="dependencyObject">The Control</param> 
/// <param name="e">The DependencyPropertyChangedEventArgs object containing event 
/// specific information.</param> 
public static void OnMyToolTipChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) 
{ 
    // What type of control - I may be able to use a generic parent that supports Tooltips, but until I have time to figure that out, using this to generate a valid control.ToolTip reference. 
    if (dependencyObject is TextBox) 
    { 
     var txtControl = dependencyObject as TextBox; 
     if (e.OldValue != e.NewValue) 
     { 
      txtControl.ToolTip = e.NewValue; 
     } 
    } 
    else if (dependencyObject is ComboBox) 
    { 
     // Add code here for ComboBox and other tooltip controls (if we can't use a parent/interface reference instead.) 
    } 
} 

конечно, есть намного больше в стиле, и т.д., но я оставил все, что таким образом, чтобы у вас было только код, необходимый для решения этой проблемы.

Надеется, что это помогает кто-то ...

(Если вы думаете, что вы можете сделать это лучше, пойти на это, тем больше идей, тем лучше)

Смежные вопросы