编辑:我创建了一个示例项目,显示了我已完成的工作和无效的工作。 https://github.com/jmooney5115/clear-multibinding
我有一个带有控件(文本框,数据网格等)的WPF应用程序。当控件上的值更改时,我需要通过更改背景色来指示它。保存更改后,背景颜色需要返回到未更改的状态,而无需重新加载控件。此应用程序不是MVVM,请不要判断我继承了它。
我有使用MultiBinding和值转换器更改颜色的完美代码。问题是我在代码中调用Save()后无法弄清楚如何重置背景。我尝试做DataContext = null,然后执行DataContext = this,但是控件闪烁。必须有更好的方法。
问:如何在不重新加载控件的情况下将背景重置为不变状态?
MultiBinding XAML-通过将字符串[]传递给BackgroundColorConverter来工作。 string [0]是OneTime绑定。字符串1是另一个绑定。
<TextBox.Background>
<MultiBinding Converter="{StaticResource BackgroundColorConverter}">
<Binding Path="DeviceObj.Name" />
<Binding Path="DeviceObj.Name" Mode="OneTime" />
</MultiBinding>
</TextBox.Background>
BackgroundColorConverter.cs
/// <summary>
/// https://stackoverflow.com/questions/1224144/change-background-color-for-wpf-textbox-in-changed-state
///
/// Property changed
/// </summary>
public class BackgroundColorConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var colorRed = (System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString("#FFB0E0E6");
var colorWhite = (System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString("White");
var unchanged = new SolidColorBrush(colorWhite);
var changed = new SolidColorBrush(colorRed);
if (values.Length == 2)
if (values[0].Equals(values[1]))
return unchanged;
else
return changed;
else
return changed;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
更新
编辑:这是数据网格单元的多重绑定。如果多重绑定转换器返回true,则将背景色设置为LightBlue。如果为false,则背景为默认颜色。
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
<!-- https://stackoverflow.com/questions/5902351/issue-while-mixing-multibinding-converter-and-trigger-in-style -->
<DataGridTextColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource BackgroundColorConverterBool}">
<Binding Path="Name" />
<Binding Path="Name" Mode="OneTime" />
</MultiBinding>
</DataTrigger.Binding>
</DataTrigger>
<Setter Property="Background" Value="LightBlue"></Setter>
</Style.Triggers>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
.
.
.
</DataGrid.Columns>
我做了这种方法来保存后重置对象的绑定。
/// <summary>
/// Update the data binding after a save to clear the blue that could be there when
/// a change is detected.
/// </summary>
/// <typeparam name="T">Type to search for</typeparam>
/// <param name="parentDepObj">Parent object we want to reset the binding for their children.</param>
public static void UpdateDataBinding<T>(DependencyObject parentDepObj) where T : DependencyObject
{
if (parentDepObj != null)
{
MultiBindingExpression multiBindingExpression;
foreach (var control in UIHelper.FindVisualChildren<T>(parentDepObj))
{
multiBindingExpression = BindingOperations.GetMultiBindingExpression(control, Control.BackgroundProperty);
if (multiBindingExpression != null)
multiBindingExpression.UpdateTarget();
}
}
}
最终更新
此问题回答了如何在DataGridCell上针对我的目的使用MultiBinding:Update MultiBinding on DataGridCell
答案 0 :(得分:1)
如果bool Saved
或其他更改,则必须将DeviceObj
属性粘贴到Name
并进行处理。
ViewModel:
public class Device : INotifyPropertyChanged
{
public string Name
{
get
{
return _name;
}
set
{
if (value != _name)
{
_name = value;
Saved = false;
NotifyPropertyChanged(nameof(Name));
}
}
}
private string _name;
public bool Saved
{
get
{
return _saved;
}
set
{
if (value != _saved)
{
_saved = value;
NotifyPropertyChanged(nameof(Saved));
}
}
}
private bool _saved = true;
public void Save()
{
//Saving..
Saved = true;
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string info)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(info));
}
}
转换器:
public class BoolToSolColBrushConverter : IValueConverter
{
private static SolidColorBrush changedBr = new SolidColorBrush(Colors.Red);
private static SolidColorBrush unchangedBr = new SolidColorBrush(Colors.Green);
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
if ((bool)value)
{
return unchangedBr;
}
}
catch (Exception)
{
}
return changedBr;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
XAML:
<TextBox Text="{Binding Name}" Background="{Binding Saved, Converter={StaticResiurce BoolToSolColBrushConverter}}" />
答案 1 :(得分:1)
IHMO MVVM解决方案(如提出的Rekshino)肯定比非MVVM解决方案更好。视图模型应注意跟踪修改后的数据。
无论如何,由于继承了此应用程序,因此必须考虑转换整个代码需要多少时间,有时这是不可能的。因此,在这种情况下,您可以在保存数据时强制每个多重绑定“刷新”。
让我们假设这是您的XAML(带有两个或多个TextBoxes
):
<StackPanel>
<TextBox Margin="5" Text="{Binding DeviceObj.Name, Mode=TwoWay}">
<TextBox.Background>
<MultiBinding Converter="{StaticResource BackgroundColorConverter}">
<Binding Path="DeviceObj.Name" />
<Binding Path="DeviceObj.Name" Mode="OneTime" />
</MultiBinding>
</TextBox.Background>
</TextBox>
<TextBox Margin="5" Text="{Binding DeviceObj.Surname, Mode=TwoWay}">
<TextBox.Background>
<MultiBinding Converter="{StaticResource BackgroundColorConverter}">
<Binding Path="DeviceObj.Surname" />
<Binding Path="DeviceObj.Surname" Mode="OneTime" />
</MultiBinding>
</TextBox.Background>
</TextBox>
<Button Content="Save" Click="Button_Click" Margin="5,10,5,10" />
</StackPanel>
单击“保存” Button
时,可以强制MultiBindings以这种方式更新其自己的目标:
private void Button_Click(object sender, RoutedEventArgs e)
{
MultiBindingExpression multiBindingExpression;
foreach (TextBox textBox in FindVisualChildren<TextBox>(this))
{
multiBindingExpression = BindingOperations.GetMultiBindingExpression(textBox, TextBox.BackgroundProperty);
multiBindingExpression.UpdateTarget();
}
}
您可以在this answer中找到FindVisualChildren
实现。希望它能对您有所帮助。