Ответы пользователя по тегу XAML
  • Как загрузить UserControl при клике на элемент ListBox?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Вам нужно просто связать датаконтекст групбоксов с выделенным элементом списка. Всё остальное сделает WPF.
    <ListBox ItemsSource="{Binding DevList}" SelectedItem="{Binding SelectedElement}" />
    <GroupBox DataContext="{Binding SelectedElement}">
    </GroupBox>
    <GroupBox DataContext="{Binding SelectedElement.Subelement1}">
    </GroupBox>


    Чтобы это заработало, то нужно сделать так, чтобы DevList был список объектов, а не строк. Создайте класс (вьюмодель) для ваших элементов списка. В нём можно хранить те свойства, которые вы хотите показывать в групбоксах. То есть, в списке элементов хранятся ваши объекты, а потом они же указываются датаконтекстом в другие контролы (групбоксы).

    В таком случае хорошо сделать во вьюмодели реализацию INotifyPropertyChanged.
    Ответ написан
  • Как включить отображение XAML Designer Window в Visual Studio 2017?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Судя по картинке, у вас студия разделила xaml и xaml.cs, а не поняла их как общую сущность. И теперь xaml показывает как простой текстовый файл. Возможно, студия не поняла, какой тип шаблона этого проекта (может, проект не созданный вновь, а подключенный существующий?).

    Создайте в этом же решении новый проект с типом WpfApplication и попробуйте дизайнер в нём. Сравните файлы csproj между вашим дефектным проектом и вновь созданным проектом.
    Ответ написан
    Комментировать
  • Как разделить код ViewModel-ей на каждое окно?

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

    Я бы попробовал в MainViewModel сделать список ViewModel-ей. Если добавляется новая модель, то добавлять в список. В MainViewModel добавить CurrentViewModel, имеющий ссылку на текущую вьюмодель, которая в данный момент нужно выводить. И в MainViewModel сделать метод, которыйпоказывает нужную вьюмодель по выбранной модели (что-то типа private ViewModel SelectModel(Model model) {}).
    Ответ написан
    Комментировать
  • Можно ли указать в одном биндинге несколько конвертеров?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Вам не нужно делать второй конвертер, а настроить тот, чтобы возвращал нужное значение - возвращать Visibility.Collapsed при истине и Visibility.Visible при лжи.
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if ((bool)value)
        {
            return parameter != null ? Visibility.Collapsed : Visibility.Hidden;
        }
        return Visibility.Visible;
    }


    А если нужно именно проверять несколько различных проверок у одного элемента, то используйте MultiBinding. Я написал об этом тут.
    Ответ написан
    9 комментариев
  • Как в xaml делать несколько конвертеров?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    В вашем случае, подойдёт создание специального кастомного конвертера, который сделает и из числа в строку, и потом строку обработает.

    Другой вариант - MultiBinding. Создаётся специальный мультиконвертер, в который указывается несколько обычных биндингов. Но они обрабатываются параллельно, поэтому, если нужно вначале делать первый конвертер, а потом использовать его результат в другом конвертере, то так не получится, все данные обрабатываются в мультиконвертере.

    Но мультибиндинг работает в WPF, а в Silverlight нет. Но для Silverlight есть workaround: www.codeproject.com/Articles/286171/MultiBinding-i...

    Вот пример мультиконвертера, который берёт несколько bool, и проверяет, все ли они истинны (или ложны - можно выбрать).

    Использование конвертера:
    xmlns:converters="clr-namespace:MyProject.Converters"
    
    <CheckBox x:Name="Checkbox1" Content="Чекбокс 1"/>
    <CheckBox x:Name="Checkbox2" Content="Чекбокс 2"/>
    <ToggleButton Content="Кнопка">
        <ToggleButton.IsEnabled>
            <MultiBinding Converter="{converters:BooleanMultiConverter Type=AllTrue}">
                <Binding Path="IsChecked" ElementName="Checkbox1"/>
                <Binding Path="IsChecked" ElementName="Checkbox2"/>
            </MultiBinding>
        </ToggleButton.IsEnabled>
    </ToggleButton>

    Сам конвертер:
    using System;
    using System.Linq;
    using System.Windows;
    using System.Windows.Data;
    using System.Windows.Markup;
    
    namespace MyProject.Converters
    {
        public class BooleanMultiConverter : MarkupExtension, IMultiValueConverter
        {
            /// <summary>
            /// Перечисление типа конвертера
            /// </summary>
            public enum Types
            {
                AllTrue,
                AllFalse,
                AnyTrue,
                AnyFalse,
            }
    
            /// <summary>
            /// Тип конвертера, по умолчанию - AllTrue
            /// </summary>
            public Types Type { get; set; }
    
            public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                switch (Type)
                {
                    case Types.AllTrue:
                        return values.All(v => (bool)v);
                    case Types.AllFalse:
                        return values.All(v => !(bool)v);
                    case Types.AnyTrue:
                        return values.Any(v => (bool)v);
                    case Types.AnyFalse:
                        return values.Any(v => !(bool)v);
                    default:
                        throw new InvalidOperationException();
                }
            }
    
            public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
            {
                return new[] { DependencyProperty.UnsetValue };
            }
    
            #region MarkupExtension
    
            public BooleanMultiConverter()
            {
            }
    
            /// <summary>
            /// Отображать конвертер в списке
            /// </summary>
            public override object ProvideValue(IServiceProvider serviceProvider)
            {
                return this;
            }
    
            #endregion
        }
    }

    MarkupExtension используется, чтобы не создавать кучу конвертеров в ресурсах
    Ответ написан
    2 комментария
  • Двойной клик по итему ListBox-а?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Нужно просто поставить привязку с командой у вашей вьюмодели. Вы ведь используете MVVM?

    Гораздо удобнее использовать не создавать вручную ICommand, а сделать класс, реализующий этот интерфейс. Обычно его называют DelegateCommand (классы указаны ниже).

    И дальше во вьюмодели создаёте свойство для команды и привязывайте то место, где нужна команда, к созданной команде во вьюмодели.

    #region Свойства
    
    public ObservableCollection<MyClass> Collection { get; set; } = new ObservableCollection<MyClass>
    {
        new MyClass { Name = "Иванов Иван" },
        new MyClass { Name = "Петров Пётр" },
        new MyClass { Name = "Сидоров Сидор" },
    };
    public MyClass SelectedCollection { get; set; };
    
    #endregion
    
    #region Команды
    
    private ActionCommand _myCommand;
    public ActionCommand MyCommand => _myCommand ?? (_myCommand = new ActionCommand(MyMethod));
    
    private DelegateCommand<MyClass> _myDelegateCommand;
    public DelegateCommand<MyClass> MyDelegateCommand => _myDelegateCommand ?? (_myDelegateCommand = new DelegateCommand<MyClass>(MyMethod2, item => item != null);
    
    private void MyMethod()
    {
        // обработка команды
    }
    
    private void MyMethod2(MyClass item)
    {
        // обработка команды
    }
    
    #endregion


    <ListBox ItemsSource="{Binding Collection}" SelectedItem="{Binding SelectedItem}"/>
    <Button Command="{Binding MyCommand}" Content="Команда 1"/>
    <Button Command="{Binding MyDelegateCommand}" CommandParameter="{Binding SelectedItem}" Content="Команда 2"/>


    Если нужна команда не на событие Сlick, а на любое другое событие (как вы говорите, на DoubleClick), то нужно сделать добавить референс на System.Windows.Interactivity и указать триггер на событие:
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

    <ListBox ItemsSource="{Binding Collection}" SelectedItem="{Binding SelectedItemc}" DisplayMemberPath="Name">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="MouseDoubleClick">
                <i:InvokeCommandAction Command="{Binding MyDelegateCommand}" CommandParameter="{Binding SelectedItem}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </ListBox>


    Класс DelegateCommand - команда с параметром, и класс ActionCommand - команда без параметра. Нешаблонный класс DelegateCommand используется реже (я вообще не припомню, чтобы его использовал).
    public class DelegateCommand<T> : ICommand
    {
        #region Private fields
    
        private readonly Action<T> _execute;
        private readonly Func<T, bool> _canExecute;
    
        #endregion
    
        #region Constructors
    
        public DelegateCommand(Action<T> execute, Func<T, bool> canExecute = null)
        {
            _execute = execute;
            _canExecute = canExecute;
        }
    
        #endregion
    
        #region DelegateCommand
    
        public void Execute(T parameter)
        {
            var handler = _execute;
            if (handler != null)
            {
                handler(parameter);
            }
        }
    
        public bool CanExecute(T parameter)
        {
            var handler = _canExecute;
            return handler == null || handler(parameter);
        }
    
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
    
        #endregion
    
        #region ICommand
    
        void ICommand.Execute(object parameter)
        {
            Execute((T)parameter);
        }
    
        bool ICommand.CanExecute(object parameter)
        {
            return CanExecute((T)parameter);
        }
    
        #endregion
    }
    
    public class DelegateCommand : DelegateCommand<object>
    {
        public DelegateCommand(Action<object> execute, Func<object, bool> canExecute = null)
            : base(execute, canExecute)
        {
        }
    }
    
    public class ActionCommand : DelegateCommand<object>, ICommand
    {
        #region Private fields
    
        private readonly Action _action;
        private readonly Func<bool> _canExecute;
    
        #endregion
    
        #region Constructors
    
        public ActionCommand(Action action, Func<bool> canExecute = null)
            : base(null, null)
        {
            _action = action;
            _canExecute = canExecute;
        }
    
        #endregion
    
        #region ActionCommand
    
        public void Execute()
        {
            var handler = _action;
            if (handler != null)
            {
                handler();
            }
        }
    
        public bool CanExecute()
        {
            var handler = _canExecute;
            return handler == null || handler();
        }
    
        #endregion
    
        #region ICommand
    
        void ICommand.Execute(object parameter)
        {
            Execute();
        }
    
        bool ICommand.CanExecute(object parameter)
        {
            return CanExecute();
        }
    
        #endregion
    }
    Ответ написан
    1 комментарий
  • Как сделать чтобы при нажатии на кнопку событие click генерировалось только для нее?

    lexxpavlov
    @lexxpavlov
    Программист, преподаватель
    Можно попробовать разделить кнопки. Grid очень легко позволяет отобразить один элемент поверх другого. Или у вас по бизнес-логике ToggleButton обязательно должен быть внутри Button?
    Ответ написан
    Комментировать