WPF, ComboBox с CheckBox'ами
От: vpk Украина http://www.codyssey.com
Дата: 20.10.10 19:52
Оценка:
Хочу сделать комбик с галочками в елементах.
Делаю так:

<ComboBox SelectedValuePath="Name">
   <ComboBox.ItemTemplate>
      <DataTemplate>
         <StackPanel Orientation="Horizontal">
            <CheckBox IsChecked="{Binding Path=EnableSync}" VerticalAlignment="Center" Margin="3" />
            <TextBlock Text="{Binding Path=Name}" VerticalAlignment="Center" Margin="3" />
         </StackPanel>
      </DataTemplate>
   </ComboBox.ItemTemplate>
</ComboBox>


Но хотелось бы, чтобы при клике по чекбоксу, он менял состояние, а не открывался комбобокс.
Можно ли так сделать?
wpf combobox checkbox
Re: WPF, ComboBox с CheckBox'ами
От: Fortnum  
Дата: 21.10.10 03:03
Оценка: 9 (1)
Здравствуйте, vpk, Вы писали:

vpk>Но хотелось бы, чтобы при клике по чекбоксу, он менял состояние, а не открывался комбобокс.

vpk>Можно ли так сделать?

Либо полностью переписав ControlTemplate ComboBox'а, либо извратиться и поменять нечто в уже созданном контроле. Дело в том, что часть слева перекрывает прозрачный ToggleButton (можешь глянуть утилиткой Snoop), который не дает клику мышки проникнуть под него. Отнять у него этот перехват невозможно. Поэтому единственный вариант — сократить его ширину, чтобы он не перекрывал наш контрол (см. код ниже). Недостаток в том, что Popup не выскакивает при клике на строчку текста, но это тоже решается. Чтобы в code-behind не было мусора, весь код можно инкапсулировать в attached-property.

void ComboBox_Loaded(object sender, RoutedEventArgs e)
{
    var comboBox = (ComboBox)sender;

    ModifyComboBoxTemplate(comboBox);
}

void ModifyComboBoxTemplate(ComboBox comboBox)
{
    var popup = (Popup)comboBox.Template.FindName("PART_Popup", comboBox);

    var root = GetRoot<ComboBox>(popup);

    var toggleButton = SearchDownFirstChild<ToggleButton>(root);

    toggleButton.SetValue(Grid.ColumnSpanProperty, 1);
    toggleButton.SetValue(Grid.ColumnProperty, 2);
}

DependencyObject GetRoot<T>(DependencyObject child) where T : DependencyObject
{
    var parent = child;

    do
    {
        parent = VisualTreeHelper.GetParent(parent);
    }
    while (parent != null && !(parent is T));

    return parent;
}
        
T SearchDownFirstChild<T>(DependencyObject parent) where T : DependencyObject
{
    var childrentCount = VisualTreeHelper.GetChildrenCount(parent);

    for (int childIndex = 0; childIndex < childrentCount; childIndex++)
    {
        var child = VisualTreeHelper.GetChild(parent, childIndex);

        if (child is T)
        {
            return (T)child;
        }
        else
        {
            child = SearchDownFirstChild<T>(child);

            if (child != null)
            {
                return (T)child;
            }
        }
    }
            
    return null;
}
Re[2]: WPF, ComboBox с CheckBox'ами
От: vpk Украина http://www.codyssey.com
Дата: 21.10.10 07:15
Оценка:
Здравствуйте, Fortnum, Вы писали:

F>Либо полностью переписав ControlTemplate ComboBox'а, либо извратиться и поменять нечто в уже созданном контроле. Дело в том, что часть слева перекрывает прозрачный ToggleButton (можешь глянуть утилиткой Snoop), который не дает клику мышки проникнуть под него. Отнять у него этот перехват невозможно. Поэтому единственный вариант — сократить его ширину, чтобы он не перекрывал наш контрол (см. код ниже). Недостаток в том, что Popup не выскакивает при клике на строчку текста, но это тоже решается. Чтобы в code-behind не было мусора, весь код можно инкапсулировать в attached-property.


Такое решение не совместимо с Aero
Во-первых combobox меняет внешний вид, но это еще можно пережить, а во-вторых клики на чекбоксе все равно не работают.
Re[3]: WPF, ComboBox с CheckBox'ами
От: Fortnum  
Дата: 21.10.10 07:29
Оценка:
Здравствуйте, vpk, Вы писали:

vpk>Такое решение не совместимо с Aero

vpk>Во-первых combobox меняет внешний вид, но это еще можно пережить, а во-вторых клики на чекбоксе все равно не работают.

Просто посмотри Snoop'ом, что надо поправить в Aero. Способ работы со сгенеренным по шаблону контролом — тот же. Там из-за эффектов и внешнего вида, наверняка, абсолютно иной ControlTemplate, чем в Luna. Я для себя решил полностью переписать ControlTemplate, когда мне это понадобилось. Правда лишился темизации и нескольких стандартных эффектов комбобокса (типа тени, я ее убрал для простоты), но все фунциклионировало. Отполировать можно и потом, хотя это смотря какая задача перед тобой стоит. Еще говорят, что Blend позволяет как-то легко эти шаблоны править, я не пробовал. Но суть та же.
Re[4]: WPF, ComboBox с CheckBox'ами
От: vpk Украина http://www.codyssey.com
Дата: 21.10.10 07:47
Оценка:
Здравствуйте, Fortnum, Вы писали:

F>Здравствуйте, vpk, Вы писали:


F>Просто посмотри Snoop'ом, что надо поправить в Aero. Способ работы со сгенеренным по шаблону контролом — тот же. Там из-за эффектов и внешнего вида, наверняка, абсолютно иной ControlTemplate, чем в Luna. Я для себя решил полностью переписать ControlTemplate, когда мне это понадобилось. Правда лишился темизации и нескольких стандартных эффектов комбобокса (типа тени, я ее убрал для простоты), но все фунциклионировало. Отполировать можно и потом, хотя это смотря какая задача перед тобой стоит. Еще говорят, что Blend позволяет как-то легко эти шаблоны править, я не пробовал. Но суть та же.


Основываясь на твоем методе и посмотрев внимательно в бленде на шаблон, нашел решение:

void ModifyComboBoxTemplate(ComboBox comboBox)
{
   var content = SearchDownFirstChild<ContentPresenter>(comboBox);

   content.SetValue(UIElement.IsHitTestVisibleProperty, true); //Именно тут проблема
}


Еще немного нужно подправить ItemTemplate, чтобы при клике по тексту открывался комбик.

<ComboBox SelectedValuePath="Name">
   <ComboBox.ItemTemplate>
      <DataTemplate>
         <StackPanel Orientation="Horizontal">
            <CheckBox IsChecked="{Binding Path=EnableSync}" VerticalAlignment="Center" Margin="3" />
            <TextBlock Text="{Binding Path=Name}" VerticalAlignment="Center" Margin="3" IsHitTestVisible="False" />
         </StackPanel>
      </DataTemplate>
   </ComboBox.ItemTemplate>
</ComboBox>
Re[5]: WPF, ComboBox с CheckBox'ами
От: vpk Украина http://www.codyssey.com
Дата: 21.10.10 07:50
Оценка:
Правда работает только в Aero
Re[6]: WPF, ComboBox с CheckBox'ами
От: Fortnum  
Дата: 21.10.10 08:34
Оценка:
Здравствуйте, vpk, Вы писали:

vpk>Правда работает только в Aero


Я говорил, что это изврат Но можно использовать VisualStyleInformation, чтобы определиться, что за начинка была сгенерирована, и применять соответствующий метод.
Re: WPF, ComboBox с CheckBox'ами
От: Vladek Россия Github
Дата: 21.10.10 09:48
Оценка: +1
Здравствуйте, vpk, Вы писали:

vpk>Хочу сделать комбик с галочками в елементах.

vpk>Но хотелось бы, чтобы при клике по чекбоксу, он менял состояние, а не открывался комбобокс.
vpk>Можно ли так сделать?

Сделать-то можно, но вот пользователю такой контрол будет, скорее всего, не удобен. Используйте или раскрывающееся меню (ContextMenu, или какую-нибудь реализацию drop-down button), или список (ListBox) с галочками. Если места мало, то можно воспользоваться Expander-ом, которому в заголовок помещать полезную информацию — будет как раз имитация подобного комбика.
Re[3]: WPF, ComboBox с CheckBox'ами
От: notacat  
Дата: 21.10.10 10:43
Оценка:
vpk>Такое решение не совместимо с Aero
чтобы все работало, надо унаследоваться от ComboBox'а, поместить этот контрол в отдельную сборку, положить туда темплейты для всех системных тем (в папке themes должны присутствовать ResourceDictionary для каждой темы с правильными названиями типа Luna.NormalColor.xaml и т.д.) и добавить к сборке атрибут [assembly: ThemeInfo(ResourceDictionaryLocation.SourceAssembly, ResourceDictionaryLocation.SourceAssembly)]. Тогда системные темы будут подхватываться на лету.
Не пробовала ни разу, было бы интересно проверить, можно ли обойтись без наследования и переобъявить системные стили для стандартного ComboBox'а.
Re[4]: WPF, ComboBox с CheckBox'ами
От: Vladek Россия Github
Дата: 21.10.10 10:55
Оценка:
Здравствуйте, notacat, Вы писали:

vpk>>Такое решение не совместимо с Aero

N>чтобы все работало, надо унаследоваться от ComboBox'а, поместить этот контрол в отдельную сборку, положить туда темплейты для всех системных тем (в папке themes должны присутствовать ResourceDictionary для каждой темы с правильными названиями типа Luna.NormalColor.xaml и т.д.) и добавить к сборке атрибут [assembly: ThemeInfo(ResourceDictionaryLocation.SourceAssembly, ResourceDictionaryLocation.SourceAssembly)]. Тогда системные темы будут подхватываться на лету.
N>Не пробовала ни разу, было бы интересно проверить, можно ли обойтись без наследования и переобъявить системные стили для стандартного ComboBox'а.

Поместить это в ресурсы Application.Resorces и все комбобоксы подхватят этот стиль в дополнение к стандартному из текущей темы.

<Style TargetType="{x:Type ComboBox}">
</Style>
Re[5]: WPF, ComboBox с CheckBox'ами
От: Fortnum  
Дата: 21.10.10 10:59
Оценка:
Здравствуйте, Vladek, Вы писали:

N>>Не пробовала ни разу, было бы интересно проверить, можно ли обойтись без наследования и переобъявить системные стили для стандартного ComboBox'а.

V>Поместить это в ресурсы Application.Resorces и все комбобоксы подхватят этот стиль в дополнение к стандартному из текущей темы.

Это лишь бантики к горькой пилюле переписывания всего ControlTemplate'а ComboBox'а целиком
Re[5]: WPF, ComboBox с CheckBox'ами
От: notacat  
Дата: 21.10.10 11:12
Оценка:
V>Поместить это в ресурсы Application.Resorces и все комбобоксы подхватят этот стиль в дополнение к стандартному из текущей темы.

V>
V><Style TargetType="{x:Type ComboBox}">
V></Style>
V>

это для текущей системной темы будет работать. Т.е. если вы написали стиль под Aero, а кто-то вашу программу запустил под Classic темой — в UI получится ерунда. Именно что надо делать стили для всех тем разные
Re[6]: WPF, ComboBox с CheckBox'ами
От: vpk Украина http://www.codyssey.com
Дата: 21.10.10 13:09
Оценка:
Здравствуйте, Fortnum, Вы писали:

F>Это лишь бантики к горькой пилюле переписывания всего ControlTemplate'а ComboBox'а целиком


Ну с Exppression Blend'ом это не проблема вообще.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.