【问题标题】:Update MultiBinding on DataGridCell更新 DataGridCell 上的 MultiBinding
【发布时间】:2018-12-08 23:13:06
【问题描述】:

我正在通过MultiBindingIMultiValueConverter 在应用程序中集成属性更改检测。因此,当用户对“DataGrid”进行更改时,DataGridCell' changes background color. My issue is that when the user saves their work I cannot remove the changed background without a screen flicker. I can doDataContext = nullthenDataContext = this` 但会导致屏幕闪烁。我无法调用更新绑定将 MultiBinding 重置为默认值。

问:如何更新 DataGridCell 上的 MultiBinding,如下所示?

不幸的是,这不是 MVVM。我创建了一个显示问题的项目:https://github.com/jmooney5115/clear-multibinding

此解决方案适用于 TextBox,但不适用于 DataGridCell:

foreach (TextBox textBox in FindVisualChildren<TextBox>(this))
{
    multiBindingExpression = BindingOperations.GetMultiBindingExpression(textBox, TextBox.BackgroundProperty);
    multiBindingExpression.UpdateTarget();
}

这是数据网格单元格的多重绑定。多值转换器采用原始值和修改后的值。如果值更改,则返回 true 以将背景颜色设置为 LightBlue。如果为 false,则背景为默认颜色。

<DataGrid.Columns>
    <DataGridTextColumn Header="Destination Tag 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>
/// https://stackoverflow.com/questions/1224144/change-background-color-for-wpf-textbox-in-changed-state
/// 
/// Property changed and display it on a datagrid.
/// 
/// Boolean Converter
/// </summary>

public class BackgroundColorConverterBool : IMultiValueConverter
{
    /// <summary>
    /// 
    /// </summary>
    /// <param name="values"></param>
    /// <param name="targetType"></param>
    /// <param name="parameter"></param>
    /// <param name="culture"></param>
    /// <returns>True is property has changed</returns>
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values[0] is null || values[1] is null) return false;


        if (values.Length == 2)
            if (values[0].Equals(values[1]))
                return false;
            else
                return true;
        else
            return true;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

更新

使用标记为我的答案的解决方案,我能够对其进行扩展以概括 UpdateState() 方法。

foreach (var prop in this.GetType().GetProperties())
    _memo[prop.Name] = prop.GetValue(this);

【问题讨论】:

    标签: c# .net wpf data-binding multibinding


    【解决方案1】:

    我不会依赖 OneTime 绑定模式和清除绑定的技巧来跟踪数据的变化。改为实现类似 Memento 模式的东西。

    添加这个在Item类中存储状态的代码:

    private Dictionary<string, object> _memo = new Dictionary<string, object>();
    public object this[string key]
    {
        get 
        {
            object o;
            _memo.TryGetValue(key, out o);
            return o;
        }
    }
    
    public void UpdateState()
    {
        _memo["Name"] = Name;
        _memo["Description"] = Description;
        _memo["Alias"] = Alias;
        _memo["Value"] = Value;
        OnPropertyChanged("Item[]");
    }
    

    要使索引器this[] 工作,您必须重命名类(例如改名为ItemVm),因为类名和成员名不能相同,并且.NET 使用"Item" 作为索引器属性名。

    请注意,索引器的通知具有"Item[]" 格式,VerifyProperty() 方法也应该修复:

    private void VerifyProperty(string propertyName)
    {
        if (propertyName == null || propertyName == "Item[]")
            return;
    

    现在,要在窗口中使用未修改的值,像这样绑定到索引器:

    <Style TargetType="{x:Type DataGridCell}">
        <Style.Triggers>
            <DataTrigger Value="True">
                <DataTrigger.Binding>
                    <MultiBinding Converter="{StaticResource BackgroundColorConverterBool}">
                        <Binding Path="Value"   />
                        <Binding Path="[Value]" />
                    </MultiBinding>
                </DataTrigger.Binding>
    
                <Setter Property="Background" Value="LightBlue"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
    

    创建项目时保存初始状态:

    for(var i = 0; i < 100; i++)
    {
        Items.Add(new ItemVm
        {
            Alias = string.Format("Item {0}", i.ToString()),
            Description = string.Format("Description {0}", i.ToString()),
            Name = string.Format("Name {0}", i.ToString()),
            Value = string.Format("Value {0}", i.ToString())
        });
        Items[i].UpdateState();
    }
    

    并在按钮单击时保存状态更改:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        UIHelper.UpdateDataBindings<Control>(this);
    
        foreach(var item in Items)
        {
            item.UpdateState();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-08
      • 2013-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-03
      • 2011-09-26
      • 1970-01-01
      相关资源
      最近更新 更多