在属性更改时进行多绑定颜色更改-如何实用地清除?

时间:2018-06-26 12:46:52

标签: c# .net database wpf multibinding

编辑:我创建了一个示例项目,显示了我已完成的工作和无效的工作。 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

2 个答案:

答案 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实现。希望它能对您有所帮助。