0

我有一部分视图是基于 TemplateSelector 的动态视图。但是,绑定不适用于 DataTemplate 中的控件。(控件确实显示在屏幕上,只是内容/文本为空)。我怀疑这是一个 DataContext 问题,但经过大量在线搜索后无法弄清楚。这是我的 XAML:

        <Grid>
            <Grid.DataContext>
                <local:MyViewModel/>
            </Grid.DataContext>
            <Grid.Resources>
                <DataTemplate x:Key="T1">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="40" />
                            <RowDefinition Height="40" />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="120" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <TextBlock Grid.Column="0"
                                   Grid.Row="0"
                                   Text="Music"
                                   Style="{StaticResource ResourceKey=textBlockStyle}" />
                        <TextBox Grid.Column="1"
                                 Grid.Row="0"
                                 Style="{StaticResource ResourceKey=textBoxStyle}"
                                 Text="{Binding Path=MusicName}" />
                    </Grid>
                </DataTemplate>
                <DataTemplate x:Key="T2">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="40" />
                            <RowDefinition Height="40" />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="120" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <TextBlock Grid.Column="0"
                                   Grid.Row="0"
                                   Text="Currency"
                                   Style="{StaticResource ResourceKey=textBlockStyle}" />
                        <ComboBox Grid.Column="1"
                                  Grid.Row="0"
                                  Style="{StaticResource ResourceKey=comboBoxStyle}"
                                  ItemsSource="{Binding Path=Currency_List}"
                                  SelectedItem="{Binding Path=Currency}" />
                    </Grid>
                </DataTemplate>
                <local:ProductTypeTemplateSelector T1="{StaticResource ResourceKey=T1}"
                                                   T2="{StaticResource ResourceKey=T2}"
                                                   x:Key="myTemplateSelector" />
            <Grid.Resources>
             <Grid.RowDefinitions>
                <RowDefinition Height="30" />
                <RowDefinition Height="*" />
                <RowDefinition Height="40"/>
                <RowDefinition Height="20" />
            </Grid.RowDefinitions>
            <!-- This biding works -->
            <TextBlock Grid.Row="0"  
                       Text="{Binding Path=MusicName}"/>
            <!-- This biding does not work -->
            <ContentControl Grid.Row="1"
                            Name="ccc"
                            Content="{Binding  Path=Product_Type}"
                            ContentTemplateSelector="{StaticResource myTemplateSelector}">
            </ContentControl>
        </Grid>

这是我的视图模型(从技术上讲,它是视图模型和模型混合在一起。我并没有真正实现完整的 MVVM 模式)

    public class MyViewModel: INotifyPropertyChanged 
    {

    public MyViewModel()
    {
        SetLists();
    }



    protected void SetLists()
    {
        SetList_Product_Type();
        SetList_Currency();
    }



    protected void SearchAndPopulate()
    {
        string query = string.Format("select * from dbo.vehicle_attributes where ticker like '%{0}%'", Search_Text);
        DataView dv = DAL.ExecuteQuery(query);
        if (dv.Count > 0)
        {
            DataRowView dvr = dv[0];
            Vehicle_Id = int.Parse(dvr["vehicle_id"].ToString());
            Product_Type = dvr["product_type_name"].ToString();
            Vehicle_Name = dvr["vehicle_name"].ToString();
            Is_Onshore = dvr["domicile_name"].ToString() == "Onshore";
            Currency = dvr["currency"].ToString();
            CUSIP = dvr["CUSIP"].ToString();
            ISIN = dvr["isin"].ToString();
            Ticker = dvr["ticker"].ToString();
            Valoren = dvr["valoren"].ToString();
            PC_Class = PC_Class_List.Find(x => x.Class_Name == dvr["class_name"].ToString());
            Implementation_Type = Implementation_Type_List.Find ( x => x.Implementation_Type_Name == dvr["implementation_type_name"].ToString());
            Price_Frequency = Price_Frequency_List.Find( x => x.Price_Frequency_Name == dvr["price_freq_name"].ToString());
            Status = Status_List.Find( x => x.Status_Name == dvr["status_name"].ToString());
            if (!string.IsNullOrEmpty(dvr["last_status_update"].ToString()))
            {
                Status_Date = DateTime.Parse(dvr["last_status_update"].ToString());
            }
            else
            {
                Status_Date = DateTime.MinValue;
            }
            switch (Product_Type)
            {
                case "Mutual Fund":
                    query = string.Format("select lf.dividend_currency, i.ticker from dbo.liquid_funds lf " + 
                                          "left join dbo.vehicles i on i.vehicle_id = lf.index_id " + 
                                          "where lf.vehicle_id ='{0}'",Vehicle_Id);
                    DataView dv_mutual_fund = DAL.ExecuteQuery(query);
                    if(dv_mutual_fund.Count > 0)
                    {
                        DataRowView dvr_mutual_fund = dv_mutual_fund[0];
                        Dividend_Currency = dvr_mutual_fund["dividend_currency"].ToString();
                        Benchmark_Ticker = dvr_mutual_fund["ticker"].ToString();


                    }
                    break;
                default:
                    break;
            }

        }
    }

    public ICommand SearchVehicleCommand
    {
        get
        {
            return new Command.DelegateCommand(SearchAndPopulate);
        }

    }




    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }


    //ProductType
    protected List<string> _product_Type_List = new List<string>();
    public List<string> Product_Type_List
    {
        get
        {
            return _product_Type_List;
        }
        set
        {
            _product_Type_List = value;
            OnPropertyChanged("Product_Type_List");
        }
    }
    protected void SetList_Product_Type()
    {
        string query = "SELECT * FROM dbo.product_types WHERE is_enabled = 1";
        DataView dv = DAL.ExecuteQuery(query);
        List<string> l = new List<string>();
        for (int i = 0; i < dv.Count; i++)
        {
            l.Add(dv[i]["product_type_name"].ToString());
        }
        Product_Type_List = l;

    }

    protected string _product_type;
    public string Product_Type
    {
        get
        {
            return _product_type;
        }
        set
        {
            _product_type = value;
            OnPropertyChanged("Product_Type");
            SetList_Implementation_Type();
        }
    }


    //Currency
    protected List<string> _currency_List = new List<string>();
    public List<string> Currency_List
    {
        get
        {
            return _currency_List;
        }
        set
        {
            _currency_List = value;
            OnPropertyChanged("Currency_List");
        }
    }
    protected void SetList_Currency()
    {
        string query = "SELECT currency FROM dbo.currencies";
        DataView dv = DAL.ExecuteQuery(query);
        List<string> l = new List<string>();
        for (int i = 0; i < dv.Count; i++)
        {
            l.Add(dv[i]["currency"].ToString());
        }
        Currency_List = l;

    }

    protected string _currency;
    public string Currency
    {
        get
        {
            return _currency;
        }
        set
        {
            _currency = value;
            OnPropertyChanged("Currency");
        }
    }



    // Music Name
    protected string _musicName;
    public string MusicName
    {
        get
        {
            return _musicName;
        }
        set
        {
            _musicName = value;
            OnPropertyChanged("MusicName");
        }
    }

    }

这是类接口(对不起上面的格式,但不知何故我不能正确):

这是我的 DelegateCommand 类:

public class DelegateCommand : ICommand
{
    private readonly Action _action;

    public DelegateCommand(Action action)
    {
        _action = action;
    }

    public void Execute(object parameter)
    {
         _action();
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }
}

这是 DataTemplateSelector:

public class MyTemplateSelector : DataTemplateSelector
{
    public DataTemplate T1 { get; set; }
    public DataTemplate T2 { get; set; }

    public override DataTemplate SelectTemplate(object item,
  DependencyObject container)
    {
        string product_type = (string)item;
        if (product_type == "Type1")
            return T1;
        else
        return T2;
    }
}
4

1 回答 1

1

DataTemplate 的 DataContext 设置为其绑定的对象。因此,在您的情况下,您的模板的 DataContext 是Product_Type并且您期望它是MyViewModel.

有一种解决方法可以满足您的需求。它使用RelativeSource绑定并FindAncester访问 Parent 对象的 DataContext。

您的 DataTemplate 绑定应如下所示:

XAML

        <DataTemplate x:Key="T1">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="40" />
                    <RowDefinition Height="40" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="120" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Column="0"
                               Grid.Row="0"
                               Text="Music"
                               Style="{StaticResource ResourceKey=textBlockStyle}" />
                <TextBox Grid.Column="1"
                             Grid.Row="0"
                             Style="{StaticResource ResourceKey=textBoxStyle}"
                             Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentControl}}, Path=DataContext.MusicName}" />
            </Grid>
        </DataTemplate>
        <DataTemplate x:Key="T2">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="40" />
                    <RowDefinition Height="40" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="120" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Column="0"
                               Grid.Row="0"
                               Text="Currency"
                               Style="{StaticResource ResourceKey=textBlockStyle}" />
                <ComboBox Grid.Column="1"
                              Grid.Row="0"
                              Style="{StaticResource ResourceKey=comboBoxStyle}"
                              ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentControl}}, Path=DataContext.Currency_List}"
                              SelectedItem="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentControl}}, Path=DataContext.Currency}" />
            </Grid>
        </DataTemplate>

来自 MSDN

Find Ancestor - 指数据绑定元素的父链中的祖先。您可以使用它来绑定到特定类型的祖先或其子类。

AncestorType属性沿着可视树向上并找到给定类型的第一个祖先,在这种情况下,它正在寻找ContentControl所需属性的路径,然后可以相对于此进行设置。

更新

将模板视为如何显示对象的指南。DataTemplate 的 DataContext 将是它被要求显示的任何对象。

在这种情况下,ContentControl 被告知显示Product_Type并根据 的值Product_Type使用特定模板。Product_Type被赋予 DataTemplate 并成为 DataContext。

WPFTutorials有一些很好的例子。

于 2013-11-13T23:18:22.510 回答