Ответы пользователя по тегу WPF
  • (WPF/C#) Получение Content из одной кнопки удаляет Content из другой. В чем проблема?

    @Sumor
    Проблема в том, что Content у кнопки - это Image (контрол). У контрола может быть только один родитель, и когда вы присваиваете его другой кнопке он просто меняет родителя - с одной кнопки на другую. Поэтому у первой кнопки изображение пропадает.
    При создании кнопки визуальные элементы (Image) нужно создавать заново. А вот загруженную картинку (BitmapImage) )можно использовать ту, которая уже загружена.
    Ответ написан
    Комментировать
  • Нужен ли INotifyCollectionChanged для коллекций если я его не использую?

    @Sumor
    Если хотите что-то проверить - создайте простой тестовый проект и посмотрите.

    Если у вас объекты реализуют INotifyPropertyChanged, то даже если они были привязаны к ItemsControl с помощью IEnumerable, привязанные (Binding) свойства в шаблоне обновятся. Они не пересоздадутся целиком, а именно обновятся те свойства, которые зависят от изменённых свойств вашего объекта. Например
    <ItemsControl>
      <ItemsControl.ItemTemplate>
        <DataTemplate>
             <TextBlock Text="{Binding Text}" Foreground="{Binding ForeColor}" />
        </DataTemplate>
      </ItemsControl.ItemTemplate>
    </ItemsControl>

    При изменении свойства Text вашего объекта обновится текст элемента. При изменении цвета - обновится цвет.

    Но если вы в ItemsSource кладёте IEnumerable, то изменения собственно коллекции не отслеживаются. ни добавление, ни удаление. Если у вас изменилась коллекция вам нужно переприсваивать её заново и тогда будут заново созданы все визуальные элементы.
    Для отслеживания изменения коллекции она должна реализовывать INotifyCollectionChanged. Вы можете за основу взять коллекции ObservableCollection<> - они уже реализуют необходимые события.
    Соответственно, если в NotifyCollectionChanged будет указано, что добавился элемент - только он и отрисуется. Если элемент удалён - он и будет удалён. Остальные элементы не будут затронуты.
    Ответ написан
    1 комментарий
  • ComboBoxMenu_SelectionChanged - стандартная реализация?

    @Sumor
    Вы определитесь у вас ListBox или ComboBox.
    В заголовке ComboBox, поэтому когда вызывается событие, у вас sender типа ComboBox, а не ListBox к которому вы приводите.
    Ответ написан
    Комментировать
  • Как группу CheckBox прибиндить к одному свойcту во ViewModel?

    @Sumor
    Во ViewModel свойство "дни недели" и ссылки для каждого дня недели для добавления и удаления в список:
    private List<System.DayOfWeek> _dayWeeks = new List<System.DayOfWeek>();
    public List<System.DayOfWeek> DayWeeks
    {
      get{return _dayWeeks;}
    }
    
    public bool HasMonday
    {
      get{ return _dayWeeks.Any(d => d  == DayOfWeek.Monday);}
      set
      {
        if(value && !HasMonday)
        {
          _dayWeeks.Add(DayOfWeek.Monday);
          OnPropertyChanged("DayWeeks");
          OnPropertyChanged("HasMonday");     
        }
        if(!value && HasMonday)
        {
          _dayWeeks.Remove(DayOfWeek.Monday);
          OnPropertyChanged("DayWeeks");
          OnPropertyChanged("HasMonday");     
        }
      }
    }
    // Дальше аналогично для других дней недели

    Могут быть нюансы с добавлением/удалением из списка от того, что DayOfWeek это enum. Нет возможности сейчас проверить.

    Есть другой вариант. Создать своё представление дней недели по битам байта: Понедельник - 1, Вторник - 2, Среда - 4, Четверг - 8, Пятница - 16, Суббота - 32, Воскресенье - 64
    Тогда свойство DayWeeks должно по get генерить List на основе битов. А свойства HasMonday и т.п. будут взводить/сбрасывать соответствующий бит.
    Ответ написан
  • Как правильно дополнить команду Application.Delete, сохранив её базовое выполнение?

    @Sumor
    Для назначения обработчиков команде нужно указать в разделе CommangBindings контрола, в котором будет вызываться эта команда или в любом из его логических предков, обработчик событий Execute и/или обработчик CanExecute.
    После этого вы привязываете команду к пункту меню, кнопке, через соответствующее свойство Command, либо указываете горячую клавишу или жест мыши через InputBindings.
    Ответ написан
  • Ошибка при открытии wpf формы?

    @Sumor
    Скорее всего у вас в создаваемом объекте Application установлено закрытие приложения при закрытии последней формы.
    У вас первая форма закрывается и в этот момент Application видит, что форм больше нет - закрывает себя. А вы тут же пытаетесь создать и запустить новую форму.
    Установите для Application.Current.ShutdownMode в OnExplicitShutdown
    Ответ написан
    Комментировать
  • Как получать данные из БД каждые 10 секунд (Entity Framework)?

    @Sumor
    Строчка usersGrid.ItemsSource = db.USER.Local.ToBindingList(); говорит о том, что конкретно этот текущий список записей из таблицы опубликовать в DataGrid. При повторном выполнении Load() у вас создаются новые списки, никак не связанные с тем, что находится сейчас в DataGrid. Поэтому обновления не происходит.
    Чтобы понять что изменилось в БД с момента прошлого считывания можно использовать, например, время изменения записи. И каждые 10 (или сколько вы захотите) секунд считывать только изменённые записи.
    Просто так изменённые записи в уже считанный и добавленный в грид список не обновить. Нужно найти среди существующих строчек те, что обновились в соответствии с запросом и изменить их реквизиты. Так как вы используете BindingList, то по идее после изменения записи в списке DataGrid должен обновить запись на экране.
    Схема может быть примерно такая:
    DataGrid на форме привязан (Binding) к один раз созданному списку сообщений типа BindingList<> или ObservableCollection<>. Сообщения, которые хранятся в этом списке должны реализовывать шаблон PropertyChanged. Список первоначально начитывается при старте формы. После создания, заполнения и привязки к DataGrid нельзя удалять/пересоздавать список. Если вам нужно его перечитать целиком - выполняете Clear() и добавляете записи заново. Далее по таймеру считываете изменённые или добавленные записи и пробегаете по вашему списку и их находите и изменяете. Отрабатывает PropertyChanged на сообщениях, отрабатывает изменение списка, отрабатывает обновление DataGrid. Если у вас считывание из базы происходит недолго, то вам достаточно использовать DispatcherTimer. Он выполняется в том же потоке где живёт DataGrid и список сообщений. Если же вас это не устраивает и вы хотите поиграть в потоки, то вам нужно использовать потокобезопасные коллекции и/или устраивать синхронизацию действий. Но это тема другого вопроса.
    Ответ написан
    Комментировать
  • Как узнать уровень в иерархии выбранного элемента в TreeView?

    @Sumor
    Когда вы программируете на WPF подразумевается, что визуальная часть является отражением вашего представления данных. Поэтому уровень иерархии выбранный элемент должен находить не среди элементов TreeViewItem, а среди родителей выбранного элемента в соответствии с моделью представления данных.
    Пример:
    class A
    {
     public string Name{get;set;}
     public A Parent {get;set;}
     public IEnumerable<A> Children
     {
      get
      {
        return AllItemsOfA.Select(a => a.Parent == this);
      }
     }
     public int Level()
     {
      int level = 0;
      var current = Parent;
      while(current != null)
      {
        current = current.Parent;
        level ++;
      }
      return level;
     }
    }

    Добавив коллекцию таких элементов в TreeView вы у выбранного элемента получите нужный вам уровень иерархии.
    Ответ написан
    Комментировать
  • Как выбрать элемент в comboBox по имени?

    @Sumor
    Items используется для "поэлементной" работы, а ItemsSource для подключения коллекций. Нельзя работать с ними одновременно - либо Items, либо ItemsSource.
    Поэтому ваш код должен преобразиться примерно в такой:
    comboBox2.SelectedIndex = (comboBox2.ItemsSource as System.Data.DataView).IndexOf("Вася");

    Но это не будет работать, так как в качестве элементов в ComboBox располагаются элементы из таблицы целиком, а не только имена. Поэтому лучше и удобнее пользоваться свойством SelectedItem, примерно так:
    comboBox2.SelectedItem = (comboBox2.ItemsSource as System.Data.DataView).Find("Вася");

    А ещё лучше через Binding связать свойство comboBox2.SelectedItem с каким-либо свойством вашей модели и использовать её.
    Ответ написан
    Комментировать
  • Как запустить WPF приложение из консоли?

    @Sumor
    using System;
    
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            Console.WriteLine("Starting WpfApplication1.exe...");
    
            var domain = AppDomain.CreateDomain("WpfApplication1Domain");
            try
            {
                domain.ExecuteAssembly("WpfApplication1.exe");
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
            finally
            {
                AppDomain.Unload(domain);
            }
    
            Console.WriteLine("WpfApplication1.exe exited, exiting now.");
        }
    }
    Ответ написан
    2 комментария
  • Как сделать изменение размера прямоугольника по MouseMove без потери производительности в WPF?

    @Sumor
    Поверх элементов создаёшь Canvas, на нём Rectangle, который будет отображать выделение.
    По нажатию кнопки мыши делаешь Rectangle видимым и фиксируешь одну точку. По MouseMove устанавливаешь вторую. Перерисовкой занимается сам WPF, новых элементов по MouseMove не появляется и рывков нет.
    Ответ написан
    1 комментарий
  • Свойство ConnectionString не инициализировано. Как исправить?

    @Sumor
    Соединение у вас работает только в рамках using. Оно же его и закрывает.
    Либо нужно создавать и долго хранить SqlConnection, скорее всего всё время работы программы.
    Либо в обработчике ButtonSave_Click заново создайте SqlConnection и присвойте его свойству adapter.Connection.

    Пересоздание SqlConnection в короткий промежуток времени не приводит к физическому пересозданию соединения с базой данных, так как провайдер какое-то время после закрытия ещё держит соединения на случай если они понадобятся.
    Ответ написан
  • WPF, Как сгенерировать таблицу наподобие Excel?

    @Sumor
    Можно примерно так. Заводишь класс с основным объектом, примерно такой:
    public class Worker
    {
    public string FIO {get;set;}
    public SpanTime WorkTime {get;set;}
    }

    Для отображения списка рабочих используете ListBox с шаблоном из двух текстбоксов:
    <ListBox x:Name="lst">
    <ListBox.ItemTemplate>
    <DataTemplate>
    <Grid>
    <Grid.ColumnDefinitions>
    <ColumnDefinition Width="100" />
    <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <TextBox Text="{Binding FIO}" />
    <TextBox Text="{Binding WorkTime}" Grid.Column="1"/>
    </Grid>
    </DataTemplate>
    </ListBox.ItemTemplate>
    </ListBox>

    И заполняете своими данными:
    lst.ItemSource = new List<Worker>() {new Worker(){FIO = "Иванов"}, new Worker(){FIO = "Петров"}};


    Но лучше найти какой-нибудь контрол табличный и работать с ним.
    Ответ написан
  • Компоненты WPF: DevExpress или Telerik?

    @Sumor
    Посмотрите ещё ComponentOne
    Русский язык для кнопок и подписей есть по-умолчанию.
    Ответ написан
    Комментировать
  • Как вывести таблицу из БД в TreeView WPF?

    @Sumor
    Нужно создать класс примерно такого вида:
    class Item
    {
      public string Name {get;set;}
      public IEnumerable<Item> Children 
      {
        get {/* тут код получения из базы подчинённых элементов*/}
      }
    }

    Получить список элементов верхнего уровня и присвоить ItemsSource у TreeView.
    У TreeView в описании шаблона для элемента (ItemTemplate) описать HierarchicalDataTemplate и указать свойство для получения подчинённых элементов в ItemsSource={Binding Children}.
    <TreeView>
      <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Children}">
          <TextBlock Text="{Binding Name}" />
        </HierarchicalDataTemplate>
      </TreeView.ItemTemplate>
    </TreeView>
    Ответ написан
    2 комментария
  • Как запретить выделение ListBoxItem в ListBox?

    @Sumor
    Если вы хотите использовать подразделы - используйте TreeView или группировку ListBox (можно указать шаблон для заголовка группы).
    Если не нравится, то у ListBoxItem есть свойство IsEnabled, которым можно отключить взаимодействие.
    Ответ написан
  • Как сделать различное контекстное меню для ListBox и ListBoxItem?

    @Sumor
    Ну собственно можно сделать так как вы хотите - у ListBox своё контекстное меню, а у элементов, описанных в ItemTemplate описать своё контекстное меню. С помощью команд пункты меню можно связать.
    Ответ написан
    Комментировать
  • Почему интерефейс не отражает измениния?

    @Sumor
    У DockPanel устанавливаете DataContext в соответствующий экземпляр Division
    Во всех биндингах внутри DockPanel не заполняете source, а прописываете только Path - на соответствующее свойство. Таким образом все биндинги будут привязаны к Division и брать из него соответствующие свойства. Как только срабатывает PropertyChanged - поменяется и соответствующий текст, цвет etc.

    Удобнее такие шаблоны всё-таки прописывать через Xaml.
    Можно пойти дальше и всю таблицу оформить через ItemsControl (ваш массив Division в ItemsSource), в ItemTemplate которого прописана ваша DockPanel. И тогда не нужно организовывать цикл для создания элементов - они создадутся сами.
    Ответ написан
  • Как реализовать список записей (постов) в WPF (C#)?

    @Sumor
    ItemsControl в качестве хранилища. Описываете ItemTemplate для отображения каждого элемента. ItemsPanel или ItemsPanelTemplate описывает "холст" - хотите плитками, хотите слева-направо, хотите сверху-вниз.
    Ответ написан
    Комментировать
  • Как установить привязку к UserControl от вьюмодели?

    @Sumor
    <Window ...>
        <Window.DataContext>
            <game:Game/>
        </Window.DataContext>
        <StackPanel>
            <local:MageControl DataContext="{Binding Red}"/> <!-- привязка к DataContext отлично работает -->
            <local:MageControl DataContext="{Binding Blue}" Turn="{Binding Turn}"/> <!-- привязка к Turn не работает! -->
        </StackPanel>
    </Window>

    Привязка без указания источника привязывается к DataContext. Смотрим внимательно на привязки:
    {Binding Red} - DataContext ещё не установлен, у родителя DataContext - Game. Поэтому будет привязка к Game.Red.
    {Binding Blue} - DataContext ещё не установлен, у родителя DataContext - Game. Поэтому будет привязка к Game.Blue.
    {Binding Turn} - DataContext будет установлен при загрузке в Game.Blue. Поэтому будет привязка к Game.Blue.Turn.
    Ответ написан
    2 комментария