WPF хороший способ сделать представление/средства редактирования?

это - просто вопрос обсудить - что лучший способ состоит в том, чтобы сделать представлением/средствами редактирования в WPF? Например, у нас есть Человек объекта объекта, который имеет некоторые опоры (имя, фамилия, адрес, телефон и т.д.). Одна презентация управления была бы представлением только для чтения. И другой имел бы представление редактирования для этого того же человека. Пример:

<UserControl x:Name="MyPersonEditor">
    <Grid>
        <Grid x:Name="ViewGrid" Visibility="Visible">
            <TextBlock Text="Name:"/>
            <TextBlock Text="{Binding Person.Name}"/>
            <Button Content="Edit" Click="ButtonEditStart_Click"/>
        </Grid>

        <Grid x:Name="EditGrid" Visibility="Collapsed">
            <TextBlock Text="Name:"/>
            <TextBox Text="{Binding Person.Name}"/>
            <Button Content="Save" Click="ButtonEditEnd_Click"/>
        </Grid>
    </Grid>
</UserControl>

Я надеюсь, что представление является четким. Эти две опции я вижу прямо сейчас

  1. две сетки с переключением видимости и
  2. TabControl без его панели заголовка

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

5
задан Jefim 15 June 2010 в 06:02
поделиться

4 ответа

Класс Automatic Lock

Я написал класс «AutomaticLock», у которого есть унаследованное присоединенное свойство «DoLock».

Установка для свойства DoLock значения true повторно шаблонизирует все текстовые поля ComboBox, флажки и т. Д. В текстовые блоки, нередактируемые флажки и т. Д. Мой код настроен таким образом, что другое присоединенное свойство может указывать произвольный шаблон для использования в заблокированном («режиме просмотра»), элементы управления, которые никогда не должны автоматически блокироваться, и т. Д.

Таким образом, одно и то же представление можно легко использовать как для редактирования, так и для просмотра . Установка одного свойства изменяет его взад и вперед, и его можно полностью настроить, поскольку любой элемент управления в представлении может запускаться по свойству «DoLock» для изменения его внешнего вида или поведения произвольным образом.

Код реализации

Вот код:

public class AutomaticLock : DependencyObject
{
  Control _target;
  ControlTemplate _originalTemplate;

  // AutomaticLock.Enabled:  Set true on individual controls to enable locking functionality on that control
  public static bool GetEnabled(DependencyObject obj) { return (bool)obj.GetValue(EnabledProperty); }
  public static void SetEnabled(DependencyObject obj, bool value) { obj.SetValue(EnabledProperty, value); }
  public static readonly DependencyProperty EnabledProperty = DependencyProperty.RegisterAttached("Enabled", typeof(bool), typeof(AutomaticLock), new FrameworkPropertyMetadata
  {
    PropertyChangedCallback = OnLockingStateChanged,
  });

  // AutomaticLock.LockTemplate:  Set to a custom ControlTemplate to be used when control is locked
  public static ControlTemplate GetLockTemplate(DependencyObject obj) { return (ControlTemplate)obj.GetValue(LockTemplateProperty); }
  public static void SetLockTemplate(DependencyObject obj, ControlTemplate value) { obj.SetValue(LockTemplateProperty, value); }
  public static readonly DependencyProperty LockTemplateProperty = DependencyProperty.RegisterAttached("LockTemplate", typeof(ControlTemplate), typeof(AutomaticLock), new FrameworkPropertyMetadata
  {
    PropertyChangedCallback = OnLockingStateChanged,
  });

  // AutomaticLock.DoLock:  Set on container to cause all children with AutomaticLock.Enabled to lock
  public static bool GetDoLock(DependencyObject obj) { return (bool)obj.GetValue(DoLockProperty); }
  public static void SetDoLock(DependencyObject obj, bool value) { obj.SetValue(DoLockProperty, value); }
  public static readonly DependencyProperty DoLockProperty = DependencyProperty.RegisterAttached("DoLock", typeof(bool), typeof(ControlTemplate), new FrameworkPropertyMetadata
  {
    Inherits = true,
    PropertyChangedCallback = OnLockingStateChanged,
  });

  // CurrentLock:  Used internally to maintain lock state
  [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  public static AutomaticLock GetCurrentLock(DependencyObject obj) { return (AutomaticLock)obj.GetValue(CurrentLockProperty); }
  public static void SetCurrentLock(DependencyObject obj, AutomaticLock value) { obj.SetValue(CurrentLockProperty, value); }
  public static readonly DependencyProperty CurrentLockProperty = DependencyProperty.RegisterAttached("CurrentLock", typeof(AutomaticLock), typeof(AutomaticLock));


  static void OnLockingStateChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
  {
    AutomaticLock current = GetCurrentLock(obj);
    bool shouldLock = GetDoLock(obj) && (GetEnabled(obj) || GetLockTemplate(obj)!=null);
    if(shouldLock && current==null)
    {
      if(!(obj is Control)) throw new InvalidOperationException("AutomaticLock can only be used on objects derived from Control");
      new AutomaticLock((Control)obj).Attach();
    }
    else if(!shouldLock && current!=null)
      current.Detach();
  }

  AutomaticLock(Control target)
  {
    _target = target;
  }

  void Attach()
  {
    _originalTemplate = _target.Template;
    _target.Template = GetLockTemplate(_target) ?? SelectDefaultLockTemplate();
    SetCurrentLock(_target, this);
  }

  void Detach()
  {
    _target.Template = _originalTemplate;
    _originalTemplate = null;
    SetCurrentLock(_target, null);
  }

  ControlTemplate SelectDefaultLockTemplate()
  {
    for(Type type = _target.GetType(); type!=typeof(object); type = type.BaseType)
    {
      ControlTemplate result =
        _target.TryFindResource(new ComponentResourceKey(type, "AutomaticLockTemplate")) as ControlTemplate ??
        _target.TryFindResource(new ComponentResourceKey(typeof(AutomaticLock), type.Name)) as ControlTemplate;
      if(result!=null) return result;
    }
    return null;
  }
}

Этот код позволит вам указать шаблон автоматической блокировки для каждого элемента управления, либо он позволит вам использовать шаблоны по умолчанию, определенные в сборке, содержащей класс AutomaticLock в сборке, содержащей ваш настраиваемый элемент управления, к которому применяется шаблон блокировки, в ваших локальных ресурсах в визуальном дереве (включая ресурсы приложения)

Как определить шаблоны AutomaticLock

Шаблоны по умолчанию для стандартных элементов управления WPF: определен в сборке, содержащей класс AutomaticLock в ResourceDictionary, объединенном в Themes / Generic.xaml. Например, этот шаблон заставляет все TextBoxes превращаться в TextBlocks при блокировке:

<ControlTemplate TargetType="{x:Type TextBox}"
  x:Key="{ComponentResourceKey ResourceId=TextBox, TypeInTargetAssembly={x:Type lc:AutomaticLock}}">
  <TextBlock Text="{TemplateBinding Text}" />
</ControlTemplate>

Шаблоны по умолчанию для настраиваемых элементов управления могут быть определены в сборке, содержащей настраиваемый элемент управления в ResourceDictionary, объединенном в его Themes / Generic.xaml. ComponentResourceKey в этом случае отличается, например:

<ControlTemplate TargetType="{x:Type prefix:MyType}"
  x:Key="{ComponentResourceKey ResourceId=AutomaticLockTemplate, TypeInTargetAssembly={x:Type prefix:MyType}}">
    ...

Если приложение хочет переопределить стандартный шаблон AutomaticLock для определенного типа, оно может разместить шаблон автоматической блокировки в своем App.xaml, Window XAML, UserControl XAML или в ResourceDictionary отдельного элемента управления. В каждом случае ComponentResourceKey следует указывать так же, как и для настраиваемых элементов управления:

x:Key="{ComponentResourceKey ResourceId=AutomaticLockTemplate, TypeInTargetAssembly={x:Type prefix:MyType}}"

Наконец, шаблон автоматической блокировки можно применить к отдельному элементу управления, установив его свойство AutomaticLock.LockTemplate .

Как использовать AutomaticLock в пользовательском интерфейсе

Чтобы использовать автоматическую блокировку:

  1. Установите AutomaticLock.Enabled = "True" для любых элементов управления, которые должны быть автоматически заблокированы. Это можно сделать в стиле или непосредственно на отдельных элементах управления. Это позволяет заблокировать элемент управления, но не приводит к его фактической блокировке.
  2. Если вы хотите заблокировать, установите AutomaticLock.DoLock = "True" в вашем элементе управления верхнего уровня (окно, представление, UserControl и т. Д.) Всякий раз, когда вы хотите, чтобы автоматическая блокировка действительно происходила. Вы можете привязать AutomaticLock.DoLock к флажку или пункту меню или управлять им в коде.

Некоторые советы по эффективному переключению между режимами просмотра и редактирования

Этот класс AutomaticLock отлично подходит для переключения между режимами просмотра и редактирования, даже если они существенно отличаются. У меня есть несколько различных методов построения представлений, позволяющих учесть различия в макете при редактировании. Вот некоторые из них:

  1. Сделать элементы управления невидимыми в режиме редактирования или просмотра, установив либо их Template, либо AutomaticLockTemplate на пустой шаблон, в зависимости от обстоятельств.Например, предположим, что «Возраст» находится вверху вашего макета в режиме просмотра и внизу в режиме редактирования. Добавьте текстовое поле для «Возраст» в обоих местах. Вверху установите для шаблона пустой шаблон, чтобы он не отображался в режиме редактирования. Внизу установите AutomaticLockTemplate на пустой шаблон. Теперь будет виден только один.

  2. Используйте ContentControl для замены границ, панелей макета, кнопок и т. Д., Окружающих контент, не затрагивая контент. Шаблон ContentControl имеет окружающие границы, панели, кнопки и т. Д. Для режима редактирования. Он также имеет AutomaticLockTemplate, который имеет версию режима просмотра.

  3. Используйте элемент управления, чтобы заменить прямоугольную часть вашего представления. (Под этим я на самом деле имею в виду объект класса «Control», а не его подкласс.) Вы снова помещаете свою версию режима редактирования в шаблон, а версию режима просмотра в шаблон AutomaticLockTemplate.

  4. Используйте сетку с дополнительными строками и столбцами с автоматическим размером. Используйте триггер для свойства AutomaticLock.DoLock, чтобы обновить свойства Row, Column, RowSpan и ColumnSpan элементов в сетке. Например, вы можете переместить панель, содержащую элемент управления «Возраст», наверх, изменив ее Grid.Row с 6 на 0.

  5. Триггер DoLock для применения LayoutTranform или RenderTransform к вашим элементам или для установки других свойств, таких как Ширина и высота. Это полезно, если вы хотите, чтобы объекты были больше в режиме редактирования, или если вы хотите сделать текстовое поле шире и переместить кнопку рядом с ним вплотную к краю.

Обратите внимание, что вы можете использовать опцию № 3 (объект Control с отдельными шаблонами для режимов редактирования и просмотра) для всего вида.Это было бы сделано, если бы режимы редактирования и просмотра были совершенно разными.В этом случае AutomaticLock по-прежнему дает вам возможность установить два шаблона вручную. Это будет выглядеть так:

<Control>
  <Control.Template>
    <ControlTemplate>
      <!-- Edit mode view here -->
    </ControlTemplate>
  </Control.Template>
  <lib:AutomaticLock.LockTemplate>
    <ControlTemplate>
      <!-- View mode view here -->
    </ControlTemplate>
  </lib:AutomaticLock.LockTemplate>
</Control>

Как правило, легче настроить несколько небольших позиций и вещей между режимами редактирования и просмотра, и это лучше для вашего взаимодействия с пользователем, потому что у пользователя будет согласованный макет, но если вам действительно нужна полная замена AutomaticLock также дает вам эту возможность.

3
ответ дан 15 December 2019 в 00:50
поделиться
<Grid>
    <TextBlock Text="Name:"/> 
    <LabelText="{Binding Person.Name}" Cursor="IBeam" MouseDoubleClick="lblName_dblClick"/>  <!-- set the IsEditMode to true inside this event -->
    <TextBox Text="{Binding Person.Name}" Visibility="{Binding IsEditMode, Converter={StaticResource BoolToVisConverter}}"/>
    <Button Content="OK" Click="btnSave_Click" Visibility="{Binding IsEditMode, Converter={StaticResource BoolToVisConverter}}"/> <!-- set the IsEditMode to false inside this event -->
</Grid>

Скорее используйте команду, если вы знакомы с.

1
ответ дан 15 December 2019 в 00:50
поделиться

Я бы создал один вид с двумя разными конфигурациями, например. 2 разных конструктора, чтобы сделать соответствующее поле редактируемым/читаемым или видимым/скрытым

Таким образом, вы не пишете лишнего XAML и можете настроить все поля через код позади или ViewModel при использовании MVVM

.
0
ответ дан 15 December 2019 в 00:50
поделиться

Мне кажется, работа для DataTemplateSelector . Если вы предпочитаете переключать отдельные элементы управления на место, я бы сделал что-то похожее на то, что предложил Вир.

0
ответ дан 15 December 2019 в 00:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: