2015-09-22 4 views
0

Я пытаюсь использовать MVVM для своего приложения, так как это упрощает работу. Таким образом, мой пункт меню - это класс данных, привязанный к кнопке с пользовательским стилем (стиль фактически связывает базовые данные).Использование управления ресурсами

Дело в том, что эти пункты меню могут иметь дополнительный контент, который может быть установлен на Collapsed, если это не необходимо. Пока это работает очень хорошо, но переход на MVVM вызывает некоторые проблемы. Мне нужно где-то определить дополнительный контент и программно настроить его на пункты меню.

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

Но когда я пытаюсь загрузить его с помощью метода FindResource(), он ничего не находит. Я помещал его в разные места и называл код в разных состояниях (конструктор Window, Loaded-event, ...), но нигде не может найти этот элемент управления.

Я пробовал его с Application.Current.Resources[...], Application.Current.FindResource(...), а также с классом Window. Он всегда появляется ResourceReferenceKeyNotFoundException.

Кроме того, при вставке файлов ресурсов это дает мне исключение синтаксического анализа, в котором говорится, что я не могу использовать x:Name для объектов ресурсов. Поэтому я в принципе не могу использовать всю систему, так как мне нужны имена, чтобы связывать вещи между дочерними элементами этого элемента управления.

Возможно ли это? Предполагается, что он будет использоваться таким образом? Есть ли лучший подход к достижению этого? Это опять та точка, где я не получаю принципы проектирования в WPF ...

PS: Я попытался с помощью Страницы и ресурсов варианты, как для компиляции .xaml-файла.

Это управление:

<views:AnimatedStackPanel x:Key="LiftMenuAnalyzeContent" HorizontalAlignment="Stretch" Orientation="Vertical" > 
<views:AnimatedStackPanel.Children> 
    <StackPanel x:Name="PaneAnalysisStep" Orientation="Horizontal" HorizontalAlignment="Center"> 
     <shared:Triangle Width="20" Height="24" ApexSide="Left" 
              Fill="#ff8000" /> 
     <Border HorizontalAlignment="Stretch" VerticalAlignment="Center" Background="#ff8000" 
           BorderBrush="#ff8000" BorderThickness="0" Padding="4"> 
      <TextBlock x:Name="TxtAnalysisStep" Text="Analyzing" /> 
     </Border> 
     <shared:Triangle Width="20" Height="24" ApexSide="Right" 
              Fill="#ff8000" /> 
    </StackPanel> 

    <Grid x:Name="GridAnalysisInfo" HorizontalAlignment="Center" VerticalAlignment="Stretch"> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="30" /> 
      <ColumnDefinition Width="10" /> 
      <ColumnDefinition Width="50" /> 
     </Grid.ColumnDefinitions> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto" /> 
      <RowDefinition Height="27" /> 
      <RowDefinition Height="27" /> 
      <RowDefinition Height="27" /> 
     </Grid.RowDefinitions> 

     <Label x:Name="LblObjectsFound" Grid.Row="1" Grid.Column="0" 
           Content="0" /> 
     <Label Grid.Row="1" Grid.Column="2" HorizontalAlignment="Left" 
           Content="Targets" /> 
     <Label x:Name="LblIssuesFound" Grid.Row="2" Grid.Column="0" 
           Content="0" /> 
     <Label Grid.Row="2" Grid.Column="2" HorizontalAlignment="Left" 
           Content="Issues" /> 
     <Label x:Name="LblErrorsFound" Grid.Row="3" Grid.Column="0" 
           Content="0" /> 
     <Label Grid.Row="3" Grid.Column="2" HorizontalAlignment="Left" 
           Content="Errors" /> 
    </Grid> 

    <TextBlock Margin="0,5,0,0" FontWeight="Bold" 
           Text="Not possible." TextAlignment="Center" TextWrapping="Wrap" /> 
</views:AnimatedStackPanel.Children> 

+1

Нет, это не правильный путь. Тот факт, что вы пытаетесь использовать «FindResource» и «Application.Current.Resources», указывает на то, что вы по-прежнему используете код, который не является MVVM. На этот вопрос практически невозможно ответить, потому что код, который вы опубликовали, не соответствует вашему описанию. Вы говорите о меню с пользовательским контентом, но XAML, который вы предоставили, представляет собой StackPanel с надписями на сетке. Что именно вы пытаетесь сделать? –

+0

Проблема не в меню. Меню прекрасно работает, стиль тоже. Если я добавлю экземпляр этого пункта меню (только свойства с INotifyChangedProperty), он правильно отобразит элемент. Но не MVVM о том, что у вас есть набор элементов, к которым вы привязываетесь, и затем автоматически создает представление из модели (в этом случае элемент меню является моделью). Поэтому я создаю эти пункты меню в коде, потому что он должен быть динамическим. Содержимое, которое я хочу добавить к этому, должно быть объявлено где-то, потому что создание этого элемента управления - это большая работа, если это делается в коде. Поэтому я должен как-то загрузить его. – SharpShade

ответ

0

Если вы хотите создать динамическое меню в MVVM, то вам нужно начать с объявлением модели представления для каждого пункта меню содержит заголовок, поле для динамическое содержимое (подробнее об этом в минуту) и список любых пунктов меню ребенка:

public class MenuItemViewModel : ViewModelBase 
{ 
    public string Header {get; set;} 
    public object Content {get; set;} 
    public MenuItemViewModel[] Children { get; set; } 
} 

Тогда ваша модель представления необходимо создать дерево из этих структур:

public class DemoViewModel : ViewModelBase 
{ 
    public MenuItemViewModel[] MenuItems {get; set;} 

    public DemoViewModel() 
    { 
     this.MenuItems = new MenuItemViewModel[] 
     { 
      new MenuItemViewModel{ 
       Header = "File", Content="icon.png", 
       Children = new MenuItemViewModel[] 
       { 
        new MenuItemViewModel{Header="Open", Content="icon.png"}, 
        new MenuItemViewModel{Header="Save", Content="icon.png"}, 
        new MenuItemViewModel{Header="Close", Content="icon.png"}, 
       } 
      }, 
      new MenuItemViewModel{ 
       Header = "Edit", Content="icon.png", 
       Children = new MenuItemViewModel[] 
       { 
        new MenuItemViewModel{Header="Cut", Content="icon.png"}, 
        new MenuItemViewModel{Header="Copy", Content="icon.png"}, 
        new MenuItemViewModel{Header="Paste", Content="icon.png"}, 
       } 
      } 
     }; 
    } 
} 

Отображение этого меню является просто вопросом привязки меню к MenuItems и указав HeirarchicalDataTemplate так, что он знает, как сделать их:

<Menu ItemsSource="{Binding MenuItems}" DockPanel.Dock="Top"> 
     <Menu.Resources> 
      <HierarchicalDataTemplate DataType="{x:Type local:MenuItemViewModel}" ItemsSource="{Binding Children}"> 
       <ContentPresenter Content="{Binding Header}" /> 
      </HierarchicalDataTemplate> 
     </Menu.Resources> 
    </Menu> 

Результат:

enter image description here

В этом примере я явно сделал отображение ContentPresenter тем, что находится в свойстве , но вы можете переопределить его на ну, что хочешь.В моей первоначальной модели представления я добавил Content свойство и установить их все icon.png, которые я предполагаю, что это ресурс, я могу отобразить его с помощью изображения с источником BitmapImage:

  <HierarchicalDataTemplate DataType="{x:Type local:MenuItemViewModel}" ItemsSource="{Binding Children}"> 
       <StackPanel Orientation="Horizontal"> 
        <TextBlock Text="{Binding Header}" /> 
        <Image Width="16" Height="16"> 
         <Image.Source> 
          <BitmapImage UriSource="{Binding Content}" /> 
         </Image.Source> 
        </Image> 
       </StackPanel> 
      </HierarchicalDataTemplate> 

Результат:

enter image description here

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

+0

Благодарим вас за подробный ответ. Я думаю, что до сих пор я прав. Ведь все работает так. Моя особая проблема здесь в том, что у меня нет иконки как содержимого, а целая иерархия элемента управления. Тот, который я опубликовал в исходном посте - это один вид контента. Но объявление этого кода в коде - одна адская работа и супер негибкая. Я хотел бы объявить его как любое представление в XAML, загрузить его в «DemoViewModel», добавить привязки к определенным элементам этой «иерархии элементов управления», а затем установить его как содержимое одного элемента меню. Но как уже упоминалось: я не могу загрузить его из ресурсов. – SharpShade

+0

Это прекрасно, просто поместите все в DataTemplate и представляйте его в своей модели просмотра с помощью специального класса. В качестве альтернативы поместите его в ControlTemplate и установите в качестве шаблона MenuItem с помощью DataTrigger. В любом случае вам никогда не придется создавать элементы управления представлением или обращаться к ресурсам непосредственно в моделях кода или просмотра. –

Смежные вопросы