2013-03-20 2 views
2

Я хотел был бы иметь возможность изменить DataTemplate, что мой пользовательский класс использует, основываясь на свойстве в ViewModel.Как изменить DataTemplate настраиваемого типа на основе свойства ViewModel?

Я не могу найти каких-либо ясных примеров, и я чувствую, что могу не знать достаточно о WPF или XAML, чтобы узнать, возможно ли это.

Свойство ViewModel: представляет ли пользователь свернутый столбец с одной стороны приложения. Если столбец свернут, я хочу показать только изображение для каждого пользователя, и если столбец будет расширен, я покажу изображение, имя и фамилию в StackPanel.

Я чувствую, что есть что-то действительно основное, что я пока еще не понимаю, и я думаю, что ищу кого-то, кто, возможно, пробовал что-то вроде этого или знает, как это сделать правильно.

User.cs
public class User 
{ 
    public string ImageFile {get; set;} 
    public string FirstName {get; set;} 
    public string LastName {get; set;} 
} 

Я использую ObservableCollection<User> держать мою коллекцию User объектов в ViewModel. Мои 2 DataTemplates, которые я хотел бы использовать. (Сейчас я просто использовать изображение по умолчанию и текст, чтобы увидеть, как она выглядит)

DataTemplates
<DataTemplate x:Key="UserCollapsed"> 
    <Image Source="/Images/anon.png" 
     Height="50" 
     Width="50" 
     Margin="0,5,0,0"/> 
</DataTemplate> 

<DataTemplate x:Key="UserExpanded"> 
    <StackPanel> 
    <Image Source="/Images/anon.png" 
      Height="50" 
      Width="50" 
      Margin="0,5,0,0"/> 
    <TextBlock Text="Firstname"/> 
    <TextBlock Text="Lastnamehere"/> 
    </StackPanel> 
</DataTemplate> 

Я пытался написать стиль, и применить это к моей ItemsControl в представлении, и я пробовал написать datatemplate, который использует триггеры, чтобы решить, какой шаблон использовать, но я не могу понять, где я ошибаюсь.

Стиль

<Style x:Key="userTemplateStyle" TargetType="ItemsControl"> 
    <Setter Property="ItemTemplate" Value="{StaticResource UserExpanded}"/> 
    <Style.Triggers> 
    <DataTrigger Binding="{Binding ColumnIsCollapsed, Source={StaticResource ViewModel}}" Value="True"> 
     <Setter Property="ItemTemplate" Value="{StaticResource UserCollapsed}"/> 
    </DataTrigger> 
    </Style.Triggers> 
</Style> 

Я получаю следующее исключение, когда я добавляю свойство Style на моем ItemsControl в XAML.

Исключение

{"Unable to cast object of type 'MS.Internal.NamedObject' to type 'System.Windows.DataTemplate'."} 

И DataTemplate, что я пытался использовать в качестве ItemTemplate от ItemsControl. (Я чувствую, что это неправильный способ пойти об этом, но я пытался так или иначе)

DataTemplate

<DataTemplate DataType="{x:Type md:CUser}"> 
    <DataTemplate.Triggers> 
    <DataTrigger Binding="{Binding ColumnIsCollapsed, Source={StaticResource ViewModel}}" Value="True"> 
     <Setter Property="DataTemplate" Value="{StaticResource UserCollapsed}"/> 
    </DataTrigger> 
    </DataTemplate.Triggers> 
</DataTemplate> 

ItemsControl

<ItemsControl Visibility="{Binding ColumnVisibility}" 
    Style="{StaticResource userTemplateStyle}" 
    BorderThickness="0" 
    Name="itcLoggedInUsers" 
    Margin="0" 
    ItemsSource="{Binding LoggedInUsers}" 
    Grid.Row="1"/> 
+0

Читайте на DataTemplateSelector, вот хороший пример http://tech.pro/tutorial/807/wpf-tutorial-how-to-use- a-datatemplateselector – Phil

+0

@Phil Да, если у вас есть пример, специфичный для моих потребностей, свойство в * ViewModel * не сама модель, то, во всяком случае, ссылка. http://tech.pro/tutorial/807/wpf-tutorial-how-to-use-a-datatemplateselector Я пытаюсь выяснить, нужен ли DataTemplateSelector, что мне нужно, и выяснил, что он не работает в мой случай AFAIK. – Zack

+0

Пример в вашей ссылке дает вам всю необходимую информацию. Посмотрите на свой собственный класс datatemplateselector, он принимает объект item и кастинг в строку. Если вы не используете строки, добавьте в свой соответствующий объект, который будет вашей моделью просмотра. Затем напишите свою логику, сравнив свойство на viewmodel и верните соответствующий шаблон данных. – failedprogramming

ответ

0

I over мысль эта проблема. Если мне нужно было показать или скрыть элемент в DataTemplate на основе свойства booleanViewModel, я мог бы просто привязать видимость элемента к свойству на ViewModel и использовать конвертер, чтобы вернуть видимость.

Решение

<DataTemplate DataType="{x:Type md:User}"> 
    <StackPanel> 
    <Image Source="/Images/anon.png" 
      Height="50" 
      Width="50" 
      Margin="0,5,0,0"/> 
    <TextBlock Text="Firstname" Visibility="{Binding ColumnIsCollapsed, Source={StaticResource ViewModel},Converter={StaticResource InvertBoolVisibility}}"/> 
    <TextBlock Text="Lastnamehere" Visibility="{Binding ColumnIsCollapsed, Source={StaticResource ViewModel},Converter={StaticResource InvertBoolVisibility}}"/> 
    </StackPanel> 
</DataTemplate> 

Преобразователь

public class InvertBoolToVisibilityConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
    var theBool = (bool)value; 
    if (theBool) 
     return Visibility.Collapsed; 
    else 
     return Visibility.Visible; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
    throw new NotImplementedException(); 
    } 
} 
0

Ваш код отлично работает для меня ...

<Window x:Class="WpfApplication8.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:WpfApplication8="clr-namespace:WpfApplication8" 
    Title="MainWindow" 
    Width="525" 
    Height="350"> 
<Window.Resources> 
    <WpfApplication8:ViewModel x:Key="ViewModel" /> 
    <DataTemplate x:Key="UserCollapsed" /> 

    <DataTemplate x:Key="UserExpanded"> 
     <StackPanel Width="200" 
        Height="200" 
        Background="Red"> 
      <TextBlock Text="Firstname" /> 
      <TextBlock Text="Lastnamehere" /> 
     </StackPanel> 
    </DataTemplate> 
    <Style x:Key="userTemplateStyle" TargetType="ItemsControl"> 
     <Setter Property="ItemTemplate" Value="{StaticResource UserExpanded}" /> 
     <Style.Triggers> 
      <DataTrigger Binding="{Binding ColumnIsCollapsed, Source={StaticResource ViewModel}}" Value="True"> 
       <Setter Property="ItemTemplate" Value="{StaticResource UserCollapsed}" /> 
      </DataTrigger> 
     </Style.Triggers> 
    </Style> 
</Window.Resources> 
<Grid x:Name="grid" DataContext="{StaticResource ViewModel}"> 
    <ItemsControl Name="itcLoggedInUsers" 
        Grid.Row="1" 
        Margin="0" 
        BorderThickness="0" 
        ItemsSource="{Binding LoggedInUsers}" 
        Style="{StaticResource userTemplateStyle}" /> 

</Grid> 

И ViewModel

public class ViewModel: INotifyPropertyChanged 
{ 
    private bool _columnIsCollapsed; 

    public ViewModel() 
    { 
     ColumnIsCollapsed = false; 
     LoggedInUsers = new ObservableCollection<User>(); 
     LoggedInUsers.Add(new User(){FirstName = "SSSSSS", LastName = "XXXXXX"}); 
    } 
    public bool ColumnIsCollapsed 
    { 
     get { return _columnIsCollapsed; } 
     set 
     { 
      _columnIsCollapsed = value; 
      OnPropertyChanged(new PropertyChangedEventArgs("ColumnIsCollapsed")); 
     } 
    } 

    public ObservableCollection<User> LoggedInUsers { get; set; } 

    public event PropertyChangedEventHandler PropertyChanged; 

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

public class User 
{ 
    public string ImageFile { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
} 
Смежные вопросы