【问题标题】:Binding null Content in ContentControl在 ContentControl 中绑定空内容
【发布时间】:2016-10-17 09:30:48
【问题描述】:

我有 ContentControl,我的 DataTemplateSelector 也支持 null 值。

<ContentControl Content="{x:Bind CurrentItem, Mode=OneWay}">
    <ContentControl.DataTemplateSelector>
        <my:DataTemplateSelector>
            <my:DataTemplateSelector.NullTemplate>
                <DataTemplate>
                    <Border Background="Red" />
                </DataTemplate>
            </my:DataTemplateSelector.NullTemplate>
            <my:DataTemplateSelector.CustomTemplate1>
                <DataTemplate>
                    <Border Background="Green" />
                </DataTemplate>
            </my:DataTemplateSelector.CustomTemplate1>
            <my:DataTemplateSelector.CustomTemplate2>
                <DataTemplate>
                    <Border Background="Blue" />
                </DataTemplate>
            </my:DataTemplateSelector.CustomTemplate2>
        </my:DataTemplateSelector>
    </ContentControl.DataTemplateSelector>                
</ContentControl>

问题是当CurrentItem变为null时,并没有调用DataTemplateSelector中的SelectTemplateCore方法。实际上 NullTemplate 只有在第一次加载控件并且 CurrentItem 为空时才被选中。

我可以用虚拟对象替换空值,但处理这个问题要困难得多。 我找到了this 解决方案,但它仅适用于 WPF(UWP 没有 Style.Triggers)

【问题讨论】:

  • 如果您使用带有显式TargetNullValue(或Converter)的Binding而不是x:Bind会返回一个虚拟值。
  • 你检查我的答案了吗?有什么问题吗?

标签: c# xaml uwp win-universal-app


【解决方案1】:

我不确定你的 ContentControl.DataTemplateSelector 是什么,我想它是 UWP 中的 ContentControl.ContentTemplateSelector

问题是当CurrentItem更改为null时,并没有调用DataTemplateSelector中的SelectTemplateCore方法。实际上 NullTemplate 只有在控件第一次加载并且 CurrentItem 为空时才会被选中。

是的,你是对的。当您稍后将CurrentItem 设置为null 时,TemplateSelector 将不会再次遇到DataTemplateSelector。您需要为CurrentItem 创建一个可为空的属性。例如:

<Page.Resources>
    <DataTemplate x:Key="NullTemplate">
        <Border Background="Red" Height="300" Width="300">
            <TextBlock Text="{Binding TemplateName}" />
        </Border>
    </DataTemplate>
    <DataTemplate x:Key="CustomTemplate1">
        <Border Background="Green" Height="300" Width="300">
            <TextBlock Text="{Binding TemplateName}" />
        </Border>
    </DataTemplate>
    <DataTemplate x:Key="CustomTemplate2">
        <Border Background="Blue" Height="300" Width="300">
            <TextBlock Text="{Binding TemplateName}" />
        </Border>
    </DataTemplate>
    <local:MyDataTemplateSelector x:Key="MyDataTemplateSelector"
                                  NullTemplate="{StaticResource NullTemplate}"
                                  CustomTemplate1="{StaticResource CustomTemplate1}"
                                  CustomTemplate2="{StaticResource CustomTemplate2}" />
</Page.Resources>

<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <ComboBox x:Name="combo" SelectionChanged="combo_SelectionChanged">
        <ComboBoxItem Content="NullTemplate" />
        <ComboBoxItem Content="CustomTemplate1" />
        <ComboBoxItem Content="CustomTemplate2" />
        <ComboBoxItem Content="SetCurrentItemToNull" />
        <ComboBoxItem Content="SetCurrentItemPropertyToNull" />
    </ComboBox>
    <ContentControl Content="{x:Bind CurrentItem, Mode=OneWay}" Margin="0,10"
                    ContentTemplateSelector="{StaticResource MyDataTemplateSelector}" />
</StackPanel>

后面的代码:

private ContentControlDataModel _CurrentItem;

public ContentControlDataModel CurrentItem
{
    get { return _CurrentItem; }
    set
    {
        if (value != _CurrentItem)
        {
            _CurrentItem = value;
            OnPropertyChanged();
        }
    }
}

public event PropertyChangedEventHandler PropertyChanged;

private void OnPropertyChanged([CallerMemberName]string propertyName = "")
{
    if (this.PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

private void combo_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var item = combo.SelectedItem as ComboBoxItem;
    switch (item.Content.ToString())
    {
        case "NullTemplate":
            CurrentItem = new ContentControlDataModel { Template = null, TemplateName = "NullTemplate" };
            break;

        case "CustomTemplate1":
            CurrentItem = new ContentControlDataModel { Template = true, TemplateName = "CustomTemplate1" };
            break;

        case "CustomTemplate2":
            CurrentItem = new ContentControlDataModel { Template = false, TemplateName = "CustomTemplate2" };
            break;

        case "SetCurrentItemToNull":
            CurrentItem = null;
            break;

        case "SetCurrentItemPropertyToNull":
            CurrentItem = new ContentControlDataModel { Template = null, TemplateName = null };
            break;

    }
}

ContentControlDataModel是这样的:

public class ContentControlDataModel
{
    public bool? Template { get; set; } //nullable property
    public string TemplateName { get; set; }
}

还有MyDataTemplateSelector

public class MyDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate NullTemplate { get; set; }
    public DataTemplate CustomTemplate1 { get; set; }
    public DataTemplate CustomTemplate2 { get; set; }

    protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
    {
        var model = item as ContentControlDataModel;
        if (model == null || model.Template == null)
            return this.NullTemplate;
        else
        {
            return (bool)model.Template ? this.CustomTemplate1 : this.CustomTemplate2;
        }
    }
}

渲染图像:

您可以通过选择ComboBox的不同项目来检查差异。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-02
    • 1970-01-01
    • 2011-09-07
    • 2010-11-16
    • 1970-01-01
    • 2012-12-20
    • 1970-01-01
    相关资源
    最近更新 更多