2015-02-08 7 views
0

Возможно, я ошибаюсь, поэтому, если я дам мне знать.Связывание с пользовательским окном Стиль в ViewModel

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

У меня уже есть все, что было разработано в моем Xaml и отлично выглядит. У меня также есть DependecyProperty, где я могу установить из своего окна, используя этот стиль. Я хочу, чтобы вход в систему отображался или не проходил через класс расширения.

Теперь мне нужно создать DependencyProperties, чтобы сохранить пользовательские данные и связать их в определении стиля окна, однако, если я установил их в стиле и поместил свойства в код позади для созданного пользовательского элемента заголовка я создал (так я мог бы обрабатывать перетаскивание и т. д.), тогда я не могу получить к ним доступ из viewmodel, чтобы установить/получить их (или, по крайней мере, я еще не смог найти способ), но если я не установлю их в стиле, «т быть так, что я знаю, чтобы установить их позже)

Так как я могу либо: 1 - доступ DependencyProperties вид с моего ViewModel (кроме, возможно, требовать, чтобы передать view к viewmodel - которым, кажется, победить Цель MVVM 2 - привяжи DependencyProperties стиля из моего окна-х Xaml - кажется, лучший вариант, но не знаете, как это сделать

EDIT: кажется, нужно еще несколько осветляющий:

I 'm building library (dll) с стилем окна (между прочим), который может быть повторно использован в нескольких проектах. Как часть стиля окна выше, у меня есть собственный пользовательский элемент управления заголовком (значок, название, системные кнопки, пользовательские системные кнопки, перетаскивание окна, изменение размера окна и вход в систему). Все работает, но вход в систему.

Войти площадь составляет поясню:

 user name here | PIC | 
    Sign in/out here | HERE | 

Это перекрывается с моей настраиваемого заголовка:

[icon] App Name  [LoginArea][Custom Buttons][System Buttons] 

Моя проблема - как связать вошедшего пользователя информации в этой области входа?

+0

Пункт 4: Почему вы должны помещать свойства в код позади? – Bijan

+0

@Bizz - может быть, это было непонятно - я имел в виду код, стоящий за моим настраиваемым элементом управления заголовком, а не код для самого приложения. Пользовательский элемент управления titlebar выполняется только с кодом (1 cs-файл) со стилем, который применяется к нему (стиль находится в словаре ресурсов xaml). Именно в этом стиле я создал «область входа», состоящую из стековой метки с 2 гипертекстовыми текстовыми блоками и управления изображением. Теперь моя проблема заключается в том, как привязать эти 3 элемента управления. Один из вариантов заключается в привязке их к dependencyproperties в коде управления, но тогда я не знаю, как изменить данные во время выполнения. – 537mfb

+0

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

ответ

0

Так что я нашел решение для этого. Учитывая мою концепцию, у меня нет пути datacontext для привязки к времени разработки библиотеки. Каждое приложение, которое будет использовать эту библиотеку, будет иметь собственный путь - поскольку эти данные должны управляться приложением, а не библиотекой. Однако я могу иметь класс, уже определенный в библиотеке для приложения.

Так что в моей библиотеке я быть_наст класс для пользовательских данных с минимумом requeired для визуализации плюс словаря для дополнительного использования, чтобы сохранить другие пользовательские данные приложения может понадобиться для его собственных целей:

class UserData : INotifyPropertyChanged { 
    .... //set private fields 

    public string DisplayName { 
     get { return ....; } 
     set { 
      if (.... != value) { 
       .... = value; 
       OnPropertyChanged(); 
      } 
     } 
    } 

    .... Other properties including an all purpose dictionary to keep custom data 
} 

С это на месте, я могу затем добавить в свой основной файл ViewModel объект типа UserData, который приложение может использовать для хранения пользовательских данных.

Тем временем мой стиль окна использует мой пользовательский элемент управления Titlebar:

<Style x:Key="WindowStyle" TargetType="{x:Type Window}"> 
    .... <!-- other settings --> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type Window}"> 
       .... <!-- other stuff --> 
       <controls:TitleBar x:Name="TitleBar" ..... /> 
       .... <!-- other stuff --> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</style> 

и стиль моего пользовательского Titlebar имеет свой логин AREA, все элементы управления должным образом переплетены в соответствии с классом я создал для пользовательских данных:

.... <!-- other stuff --> 
<TextBlock Text="{Binding Path=DisplayName}" /> 
.... <!-- other stuff --> 

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

private void MainWindow_OnLoaded(object sender, RoutedEventArgs e) 
{ 
    var titlebar = (Control)Template.FindName("TitleBar", this); 
    titlebar.DataContext = (DataContext as MyMainViewModelType).LoggedUserData; 
} 

С MyMainViewmodelType является классом моего главного окна ViewModel и LoggedUserData свойства в пределах этого ViewModel типа UserData (мой класс с самого начала) с пользовательскими данными.

Класс UserData должен по умолчанию для создания экземпляра всех свойств, так что перед входом в нет никаких проблем с тем, что показан

+0

Это решение, безусловно, будет работать, но как-то ограничено. MainWindow, в котором размещается MainWindow_OnLoaded, не обязательно должен знать о его стиле. Это означает, что если вы хотите добавить другие стили для своего окна (например, набор тем), вы должны войти с одним и тем же именем LoginBar во всех них. – Bijan

+0

@Bizz - не совсем - любые темы в стиле окна должны были бы использовать мой элемент управления titlebar, чтобы иметь всю логику или не использовать его, и создавать свой заголовок с нуля, а любые темы в элементе управления titlebar могут использовать мой класс, в все или частично, для привязок к логину, используйте свой собственный стиль входа/логин и соответствующие привязки или вообще не имеют логин - все это развязано так, как я это сделал – 537mfb

+0

@Bizz - как для MainWindow_OnLoaded - да, это своего рода недостаток но я не вижу в этом проблемы. Все это означает, что представление знает, что у него есть элемент управления TitleBar (я не вижу проблемы, поскольку элемент управления является объектом представления), и он знает, что он должен установить datacontext для этого элемента управления (это я мог бы изменить, но не смог это сделать) - ваше решение заставляет View требовать, чтобы ViewModel владел объектом определенного типа с определенным именем (здесь я считаю, что мой немного лучше - хотя можно было пренебрежимо) – 537mfb

1

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

MainWindow в главном приложении:

<Window Style="{StaticResource myWindow}"> 
</Window> 

MainWindow код позади: (это где вид модели установлен)

public MainWindow() 
{ 
    InitializeComponent(); 
    var vm = new MainVm(); 
    vm.Login = new LoginVm(); 
    vm.Login.Username = "please enter username"; 
    DataContext = vm; 
} 

Смотреть модели: (MainVm содержит экземпляр LoginVm)

public class MainVm : DependencyObject 
{ 
    /// <summary> 
    /// Gets or sets a bindable value that indicates Login 
    /// </summary> 
    public LoginVm Login 
    { 
     get { return (LoginVm)GetValue(LoginProperty); } 
     set { SetValue(LoginProperty, value); } 
    } 
    public static readonly DependencyProperty LoginProperty = 
     DependencyProperty.Register("Login", typeof(LoginVm), typeof(MainVm), 
     new PropertyMetadata(null)); 
} 
public class LoginVm : DependencyObject 
{ 
    /// <summary> 
    /// Gets or sets a bindable value that indicates Username 
    /// </summary> 
    public string Username 
    { 
     get { return (string)GetValue(UsernameProperty); } 
     set { SetValue(UsernameProperty, value); } 
    } 
    public static readonly DependencyProperty UsernameProperty = 
     DependencyProperty.Register("Username", typeof(string), typeof(LoginVm), 
     new PropertyMetadata("")); 
} 

НазваниеBar CustomControl в вашей библиотеке: (имущество добавлено)

public class TitleBar : Control 
{ 
    static TitleBar() 
    { 
     DefaultStyleKeyProperty.OverrideMetadata(typeof(TitleBar), new FrameworkPropertyMetadata(typeof(TitleBar))); 
    } 
    /// <summary> 
    /// Gets or sets a bindable value that indicates Username 
    /// </summary> 
    public string Username 
    { 
     get { return (string)GetValue(UsernameProperty); } 
     set { SetValue(UsernameProperty, value); } 
    } 
    public static readonly DependencyProperty UsernameProperty = 
     DependencyProperty.Register("Username", typeof(string), typeof(TitleBar), new PropertyMetadata("default")); 
} 

ресурсов Словарь в библиотеке: (обратите внимание на обязательные пути)

<Style TargetType="Window" x:Key="myWindow"> 
    <Setter Property="Background" Value="WhiteSmoke"/> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate> 
       <StackPanel> 
        <ToolBar> 
         <local:TitleBar DataContext="{Binding Login}"/> 
        </ToolBar> 
       </StackPanel> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 
<Style TargetType="{x:Type local:TitleBar}"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type local:TitleBar}"> 
       <TextBox Text="{Binding Username}"/> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

Если это то, что вы хотите, то вы можете добавить дополнительные свойства и команды в так же. Надеюсь, это полезно.

+0

+1 очень похоже на то, с чем я вышел (я набрал свой ответ, когда вы ответили). Разница заключается в том, что мое решение более общее (как я и хотел), позволяя Windows без входа вообще, а также те, у кого есть логин, чтобы дать какое-либо свойство (правильного типа) как datacontext заголовка oposed к требованию 'Login' специфически специфически – 537mfb

+0

Я согласен, оба решения имеют некоторые недостатки. Правильный способ может заключаться в создании настраиваемого элемента управления, оснащенного пользователем/pass, как реквизиты зависимостей, чтобы их можно было установить из основного приложения. однако в этом случае он странно показывает черный экран, когда пользовательский элемент управления выводится из окна. Я не мог заставить его работать. – Bijan

+0

Вы хотите создать пользовательский элемент управления окном, а затем вместо 537mfb

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