【问题标题】:Add item to itemssource if no match from binding如果绑定不匹配,则将项目添加到 itemssource
【发布时间】:2013-04-19 14:32:41
【问题描述】:

所以,这是我的场景:我有一个ComboBox,其中itemssource 是各种标题及其ID 的Dictionary<int, string>。这些标题可以在将来的某个时候禁用,因此不应再显示在 ComboBox 中。但是,在查看旧项目时,除了当前活动的标题外,我仍然需要能够显示这个旧值。我将尝试在下面更好地可视化。

今天:

ComboBox 项目包括

  • 1,标题1
  • 2,标题2
  • 3,标题3

Title3 被选中,ID (3) 被存储。

明天:

Title3 被禁用,Title4 被添加,所以现在的项目包括

  • 1,标题1
  • 2,标题2
  • 4,标题4

但是,如果我们昨天的值是我们绑定的值 (ID 3),则没有匹配项。理想情况下,我想像这样将我们的旧项目附加到末尾:

  • 1,标题1,
  • 2,标题2
  • 4,标题4
  • 3,标题3

启用和禁用标题显然会有单独的列表,任何未正确绑定的项目都可以引用禁用标题变量。

我已经调查了fallbackValues 甚至PriorityBindings,但似乎无法找到一种方法让它们适合我正在尝试做的事情。也许某种转换器与fallbackValue 一起使用?感谢您的帮助和反馈。

另外,作为参考,这是我目前正在使用的代码(我希望在数据网格中执行此操作)。

WPF:

<DataGridTemplateColumn x:Name="tkTitle" Header="Title" Width="150">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ComboBox ItemsSource="{Binding DataContext.TaskTitles, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}}}" SelectedValue="{Binding Path=tkttID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedValuePath="Key" DisplayMemberPath="Value" Width="Auto" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

ViewModel 中的相关代码:

public Dictionary<int, string> TaskTitles
{
    get
    {
        return BestClass.taskTitles;
    }
}

编辑 - 工作代码 这是我用来让一切正常工作的代码。 ItemsSource 已更新为带有转换器的 MultiBinding。 MultiBinding 包含活动任务标题、所有任务标题和 ID。这些都被传递给转换器,因此在活动列表中检查 ID,如果它不活动则添加。感谢大家的帮助!

WPF

<DataGridTemplateColumn x:Name="tkTitle" Header="Title" Width="150">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ComboBox SelectedValue="{Binding Path=tkttID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedValuePath="Key" DisplayMemberPath="Value" Width="Auto">
                <ComboBox.ItemsSource>
                    <MultiBinding Converter="{StaticResource CheckDisabledTaskTitle}" Mode="OneWay">
                        <MultiBinding.Bindings>
                            <Binding Path="DataContext.TaskTitles" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}}" />
                            <Binding Path="DataContext.AllTaskTitles" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}}" />
                            <Binding Path="tkttID" />
                        </MultiBinding.Bindings>
                    </MultiBinding>
                </ComboBox.ItemsSource>
            </ComboBox>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

转换器的代码隐藏

class CheckDisabledTaskTitle : IMultiValueConverter
{
    //values[0] - Active values
    //values[1] - All values (including disabled)
    //values[2] - Current ID
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        //Check to see if the active values contain our current ID
        if (((Dictionary<int, string>)values[0]).ContainsKey((int)values[2]))
        {
            //They do, so return just the active values
            return values[0];
        }
        else
        {
            //They don't, so we'll add only our disabled value to the active list
            ((Dictionary<int, string>)values[0]).Add((int)values[2], ((Dictionary<int, string>)values[1])[((int)values[2])]);
            //Then give that back
            return values[0];
        }
    }

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

【问题讨论】:

    标签: c# wpf datagrid combobox fallbackvalue


    【解决方案1】:

    我认为您需要在 ViewModel 中修改您的集合,以便您...

    1. 加载允许的值(任务标题)
    2. 检查允许值中的选定值 (tkttID)。如果不存在,则添加它。

    为此,您应该为 TaskTitles 提供一个带有 setter 的自动属性,以便您可以在其他地方管理其内容..

    例如...(以下未经测试,因为我没有 VS atm)。我也在下面使用了Linq,即 我认为是 .NET 3 及更高版本。

    public Dictionary<int, string> TaskTitles {get;set;}
    
    public void Initialise()
    {
    TaskTitles = new Dictionary<int, string>();
    
    foreach(var taskTitle in BestClass.taskTitles)
        TaskTitles.Add(taskTitle);
    
    if(!TaskTitles.Any(t => t.Value == tkttid.Value))
        TaskTitles.Add(tkttid);
    
    
    
    }
    

    请注意,您并未添加到 BestClass.taskTitles,因此该集合不会受到影响。您正在创建一个新集合并添加相同的值,以及(可能)另一个值。

    【讨论】:

    • 您能详细说明一下使用 setter 的 auto 属性吗?不熟悉。谢谢!
    • 自动属性只是没有支持字段的属性.... public string MyProperty {get;set;} (在您的示例中,您的“支持字段”是 BestClass.TaskTitles).. “ {get;set;}" 部分是使它成为自动属性的原因......而 setter 我的意思是“set;”位 - 意味着您可以从代码中的其他位置设置属性...即属性是可写的
    • 附注它不一定是汽车属性,它只是看起来比替代品更好......见stackoverflow.com/questions/9304/…
    • 哦,好吧,我知道它们是什么,只是没有把两个和两个放在一起。我现在明白了,但我没有关注你如何将 tkttID 传递给初始化方法......
    • 好吧,这取决于你 ;) .... 我还没有看到你的完整代码,所以我不知道,但我假设你的视图模型可以访问该字段,因为你绑定到它。
    【解决方案2】:

    如果我明白你在这里的目的......

    1) 我认为您应该修改视图模型中的内容 - 如果结果为空或为空,请提供 default(您需要实现 INotifyPropertyChanged 以通知那里的更改等.)。

    2) 另一种选择是某种转换器 - 它采用您的列表属性并使用MultiBinding

    有关详细信息,请参阅我的这篇文章(主要是那里的代码)- refreshing Value Converter on INotifyPropertyChanged

    基本上,您绑定了正确的属性列表 - 和“默认列表” - 在转换器内部,您可以决定要做什么。

    例如:

    <ComboBox  ...>
        <ComboBox.ItemsSource>
            <MultiBinding Converter="{StaticResource ImageConverter}" Mode="OneWay">
                <MultiBinding.Bindings>
                    <Binding Path="TaskTitles" />
                    <Binding Path="FallbackTitles" />
                    <!--Binding Path="" /-->
                </MultiBinding.Bindings>
            </MultiBinding>
        </ComboBox.ItemsSource>
    </ComboBox>
    

    【讨论】:

    • 我认为我在使用您在此处提供的内容方面取得了一些不错的进展,但遇到了障碍。我正在尝试将 tkttID 传递给转换器,所以在那里我可以检查它是否被禁用并相应地添加额外的标题,但是我得到一个异常添加到 ConverterParameter 的绑定。我可能以错误的方式处理此问题,但希望得到一些指导。
    • 只要我有时间-np :)-您是否将转换器实现为IMultiValueConverter?它需要一组值 - 只是有点不同。如果它没有帮助,尝试一些东西并提供一些代码,我会检查并告诉你。
    • 我认为这个解决方案有你需要的一切——它是处理更复杂情况的标准模式,在转换器中传递更多变量来“做出选择”(或传递 this 等。 - 你可以用'注释行'来做到这一点 - 如果需要,它会传递整个视图模型)
    • 啊,好吧,在额外绑定中传递 ID 是我需要知道的!非常感谢您的帮助!我将使用最终工作的代码更新我的问题。
    猜你喜欢
    • 2012-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-12
    • 2021-10-12
    • 1970-01-01
    相关资源
    最近更新 更多