Мелкие проблемы на wpf

WPF
  1. 5 года назад

    Здравствуйте, У меня накопилось парочку вопросов по wpf может кто поможет мне из разрешить.
    1. Столкнулся с моментом что надо сделать активацию контролла по инверсному сосотоянию checkbox, т.е. флажок в checkbox установлен, датагрид enabled=false, и на оборот. Смысл в том что при помощи binding с легкостью можно сделать вот так

            <StackPanel Orientation="Horizontal" Grid.Row="1" VerticalAlignment="Center" Width="Auto">
                <CheckBox Name="cb_en" Content="Вот этот флажок должен отключать соседний textbox" VerticalAlignment="Center"/>
                <TextBox Text="Это тот самый текстбокс который отключается когда в checkbox стоит флажок" VerticalAlignment="Center" Width="Auto" IsEnabled="{Binding IsChecked, ElementName=cb_en}" />
            </StackPanel>

    но на самом деле требуется что то типа

    IsEnabled="{Binding -IsChecked, ElementName=cb_en}"
    IsEnabled="{Binding not IsChecked, ElementName=cb_en}"

    Никто конечно не отменял вариант управления доступностью элементов по событию изменения статуса ( в коде писать), но хотелось бы использовать все таки модель привязок. есть еще вариант написать конвертор значений, но я не пойму как это делать.
    2. Есть 2 связанные таблицы, например сотрудники с набором полей фамилии имени отчества и ид, а также таблица выдачи премии (например) где есть поле ид сотрудника который получил премию и ее величина. Смысл в том что когда я связываю эти значения в datagride вот так

                    <DataGridComboBoxColumn
                        ItemsSource="{Binding Source={StaticResource FIO}}" 
                        Header="Фамилия"
                        SelectedValueBinding="{Binding FIOID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                        SelectedValuePath="ID"
                        DisplayMemberPath="Family"
                        Width="Auto"/>

    то при попытке отсортировать по этому полю сортировка проводится не по значению коллекции FIO.Family, а по значению FIOID и результат получается непредсказуемый. есть вариант использовать SortMemberPath="" но что именно туда заносить не пойму, логично было бы Family, но это не правильно получается так как он требует поле из datacontext.
    3. Необходимо было что бы в datepicker можно было выбрать только месяц, то есть нажимаете на получить дату, открывается календарь с сеткой месяцев, а не дней и после щелчка на любой месяц окно календаря закрывается и в текстовое поле заносится надпись вида "май 2014"
    Если в контролле calendar мне еще получилось добиться того что бы выбирался только месяц,(необходим так же контроль свойства DisplayMode="Year" то в datepicker у меня этого не получилось
    По идее выходом является создание новой группы компонентов из календаря и текстбокса с прописыванием полной логики, но хотелось бы использовать компонент datepicker, наверняка можно его заставить себя вести так как хочется.
    пока все может еще что вспомню напишу.
    ps для тестов тут вот есть проект который демонстрирует эти проблемы (MS VisStudio 2013)

  2. Alexandr_Erohin

    May 14 Администратор

    1 вопрос: нужно использовать конвертер:

    namespace WpfApplication1
    {
        [ValueConversion(typeof(bool), typeof(bool))]
        public class InverseBooleanConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter,
                System.Globalization.CultureInfo culture)
            {
                if (targetType != typeof(bool))
                    throw new InvalidOperationException("Тип должен быть bool");
    
                return !(bool)value;    // инверсия логич. значения
            }
    
            public object ConvertBack(object value, Type targetType, object parameter,
                System.Globalization.CultureInfo culture)
            {
                throw new NotSupportedException();
            }
        }
    }
    <Window x:Class="WpfApplication1.MainWindow"
            xmlns:local="clr-namespace:WpfApplication1"
            ... >
        <Window.Resources>
            <!-- Ссылка на конвертер -->
            <local:InverseBooleanConverter x:Key="InverseBooleanConverter" />
        </Window.Resources>
       <StackPanel ...>
                <CheckBox Name="cb_en" .../>
                <TextBox ...
                         IsEnabled="{Binding Path=IsChecked, ElementName=cb_en, Converter={StaticResource InverseBooleanConverter}}" />
            </StackPanel>
        </Grid>
    </Window>

    2 вопрос: извините, наш штатный экстрасенс заболел, мне не удалось запустить проект который вы скинули (возможно простой архив с исходниками изменит эту ситуацию...)

    3 вопрос:

    <DatePicker CalendarOpened="datepicker_CalendarOpened"  />
    private void datepicker_CalendarOpened(object sender, RoutedEventArgs e)
    {
                var datepicker = sender as DatePicker;
                if (datepicker != null)
                {
                    // PART_Popup - часть шаблона DatePicker
                    var popup = datepicker.Template.FindName(
                        "PART_Popup", datepicker) as System.Windows.Controls.Primitives.Popup;
    
                    if (popup != null && popup.Child is Calendar)
                    {
                        Calendar calendar = (Calendar)popup.Child;
                        calendar.DisplayMode = CalendarMode.Year;
                    }
                }
    }
  3. Добавлено 5 года назад Alexandr_Erohin

    Спасибо большое за ответ. wpf предлагает поистине большие возможности, единственное надо уметь их применять.

    Найти это сообщение Alexandr_Erohin 2 вопрос: извините, наш штатный экстрасенс заболел, мне не удалось запустить проект который вы скинули (возможно простой архив с исходниками изменит эту ситуацию...)

    Иронию понял, но вот только в аттаче в формате rar архива (самораспаковывающийся) и есть исходный код проекта, правда я сейчас понимаю что для демонстрации впихнул туда еще проект небольшой бд на MS sql server. При построении возможно он захочет эту базу развернуть вследствии чего получится ошибка, но там вполне рабочий проект.

    Найти это сообщение Alexandr_Erohin 3 вопрос:

    <DatePicker CalendarOpened="datepicker_CalendarOpened"  ></DatePicker>

    private void datepicker_CalendarOpened(object sender, RoutedEventArgs e) { var datepicker = sender as DatePicker; if (datepicker != null) { // PART_Popup - часть шаблона DatePicker var popup = datepicker.Template.FindName( "PART_Popup", datepicker) as System.Windows.Controls.Primitives.Popup; if (popup != null && popup.Child is Calendar) { Calendar calendar = (Calendar)popup.Child; calendar.DisplayMode = CalendarMode.Year; } } }

    при щелчке на открытом календаре происходит переход к числам, что бы этого не происходило необходимо контролировать событие displaymodechange или что нить подобное, подскажите как добраться до него. и как в поле datepicker отобразить дату в виде "май 2014" (MMMM yyyy)

  4. Появился еще вопрос:
    В бд в таблице есть строковое поле с номером телефона в виде 9102221234, как можно в столбце датагрида выводить его в виде (910)222-12-34. Хотел использовать stringFormat = {}{0:\(###\)###\-##\-##} но почему то это не срабатывает (потом вычитал что это сработает если номер хранится как число, а если как строка то stringformat игнорируется.
    Спасибо

  5. Alexandr_Erohin

    May 14 Администратор

    pilik В бд в таблице есть строковое поле с номером телефона в виде 9102221234, как можно в столбце датагрида выводить его в виде (910)222-12-34. Хотел использовать stringFormat = {}{0:\(###\)###\-##\-##} но почему то это не срабатывает (потом вычитал что это сработает если номер хранится как число, а если как строка то stringformat игнорируется.
    Спасибо

    Чтобы не плодить вопросы отмечу вам важное правило, используемое в приложениях WPF: "Если возникает проблема с форматом вывода данных практически всегда приходиться использовать конверторы, т.к. это максимально гибкое средство". Т.е. решение будет аналогично первому вопросу в этой теме, для номера телефона нужно использовать конвертер с регулярным выражением:

    [ValueConversion(typeof(string), typeof(string))]
    public class PhoneParseConverter : IValueConverter
    {
            public object Convert(object value, Type targetType, object parameter,
                System.Globalization.CultureInfo culture)
            {
                if (targetType != typeof(string) || value == null)
                    throw new InvalidOperationException();
    
                string pattern = @"(\d{3})(\d{3})(\d{2})(\d{2})";
                return Regex.Replace((value as string), pattern, "($1)$2-$3-$4");
            }
    
            public object ConvertBack(object value, Type targetType, object parameter,
                System.Globalization.CultureInfo culture)
            {
                throw new NotSupportedException();
            }
     }

    pilik при щелчке на открытом календаре происходит переход к числам, что бы этого не происходило необходимо контролировать событие displaymodechange или что нить подобное, подскажите как добраться до него. и как в поле datepicker отобразить дату в виде "май 2014" (MMMM yyyy)

    Стандартный элемент управления DatePicker не предлагает встроенных средств форматирования даты, для этого нужно будет менять шаблон элемента управления (заодно и настроить поведение, чтобы отображались только месяцы)

  6. Найти это сообщение Alexandr_Erohin Чтобы не плодить вопросы отмечу вам важное правило, используемое в приложениях WPF: "Если возникает проблема с форматом вывода данных практически всегда приходиться использовать конверторы, т.к. это максимально гибкое средство". Т.е. решение будет аналогично первому вопросу в этой теме, для номера телефона нужно использовать конвертер с регулярным выражением:

    Да я боялся использовать конверторы ввиду непонимания как их написать, сейчас все стало довольно прозрачно с их использованием, не могли бы вы еще привести конвертор с несколькими входными параметрами ( типа объединения Фамилии Имени и Отчества в одну строку). Не могу понять как ее написать и использовать, надо ли писать его [конвертор] через multibinding.

    Найти это сообщение Alexandr_Erohin Стандартный элемент управления DatePicker не предлагает встроенных средств форматирования даты, для этого нужно будет менять шаблон элемента управления (заодно и настроить поведение, чтобы отображались только месяцы)

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

  7. Добавлено 5 года назад pilik

    Сегодня возникла еще одна интересная проблемка в виде выделения цветом ячеек datagrid содержащих даты, те даты что приходятся на выходные должны быть окрашены в красный цвет.
    Столбцов с датами 12 (месяцы). Вроде бы все нормально и конвертор написал( позже код скину) и вроде работает (правда пришлось делать 12 стилей на каждый столбец(месяц), и ячейки выделяются, но проблема в том что из бд возвращаются так же вместо дат значение null, в конверторе так же это обрабатывается и возвращается значение new solidbrush(colors.white), но все тормозит и в окне вывода (в visual studio) появлюятся отчеты об исключения приложения, в связи с чем все и тормозит. Исключение происходит сразу после выхода из конвертора.
    в связи с чем возникает вопрос, как же все таки правильно сделать выделения фона ячеек датагрида в нескольких столбцах, в зависимости от значения.
    зы Наткнулся так же на триггер, но так и не смог понять можно ли его адаптировать под это, он срабатывает вроде только при изменении свойства.
    ззы делал по образу вот этой статейки

или зарегистрируйтесь чтобы ответить