Vijay Nirmal
Vijay Nirmal

Reputation: 5837

How to Bind ItemsSource of ComboBox in ControlTemplate?

Situation

I have to change the content of the Flyout Item in GridView. So I am creating ControlTemplate in Page.Resources and setting it in ContentControl which is inside Flyout.

Problem

I have a ComboBox in ControlTemplate. Now I want to set the ItemsSource of ComboBox to List<string> (_easingType) which is declared in MainPage

Question

How to Bind/Set ItemsSource of ComboBox in ControlTemplate?

Code

I have removed the unnecessary parts of the code

XAML

<Page.Resources>
    <ControlTemplate x:Key="BlurEditFlyout">
        ....
        <ComboBox ItemsSource="{Bind it to the _esaingType}" />
        ....
    <ControlTemplate x:Key="BlurEditFlyout">
</Page.Resources>

<GridView ItemsSource="{x:Bind _items}">
    <GridView.ItemTemplate>
        <DataTemplate x:DataType="local:MethodData">
            <StackPanel>
                ....
                <Button Visibility="{x:Bind EditButtonVisibility}">
                    <Button.Flyout>
                        <Flyout>
                            <Flyout.FlyoutPresenterStyle>
                                <Style TargetType="FlyoutPresenter">
                                    <Setter Property="ScrollViewer.HorizontalScrollMode" Value="Disabled" />
                                    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
                                </Style>
                            </Flyout.FlyoutPresenterStyle>
                            <ContentControl Template="{x:Bind FlyoutTemplate}"/>
                        </Flyout>
                    </Button.Flyout>
                    <SymbolIcon Symbol="Edit"/>
                </Button>
                ....
            </StackPanel>
        </DataTemplate>
    </GridView.ItemTemplate>
</GridView>

Code Behind

public sealed partial class MainPage : Page
{

    ObservableCollection<MethodData> _items = new ObservableCollection<MethodData>();
    List<string> _easingType = new List<string>(Enum.GetNames(typeof(EasingType)).ToArray());
    Dictionary<MethodName, ControlTemplate> _buttonFlyoutDictionary = new Dictionary<MethodName, ControlTemplate>();

    public MainPage()
    {
        this.InitializeComponent();

        LoadFlyoutResources();

        _items.Add(GetMethodData(MethodName.Blur));
    }

    private void LoadFlyoutResources()
    {
        _buttonFlyoutDictionary.Add(MethodName.Blur, (ControlTemplate)Resources["BlurEditFlyout"]);
        .....
    }

    private MethodData GetMethodData(MethodName methodName)
    {
        _buttonFlyoutDictionary.TryGetValue(methodName, out ControlTemplate flyoutTemplate);
        return new MethodData(methodName, flyoutTemplate);
    }
}

public class MethodData
{
    public string Name { get; set; }
    public ControlTemplate FlyoutTemplate { get; set; }
    public Visibility EditButtonVisibility { get; set; }

    public MethodData(MethodName name, ControlTemplate flyoutTemplate)
    {
        Name = name.ToString();
        FlyoutTemplate = flyoutTemplate;
        EditButtonVisibility = (name == MethodName.Then) ? Visibility.Collapsed : Visibility.Visible;
    }
}

public enum MethodName
{
    Blur,
    ....
}

Full Code

AnimationSetSamplePage.zip

Upvotes: 2

Views: 1169

Answers (2)

TTat
TTat

Reputation: 1496

Your DataContext in the Flyout control is actually each item in "_items". You'll want to create a DataContext proxy to get to your Page's DataContext. You can follow either of these two links to create the proxy.

https://weblogs.asp.net/dwahlin/creating-a-silverlight-datacontext-proxy-to-simplify-data-binding-in-nested-controls

http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/

The gist of it is you'll want to create a proxy that you can reference as a static resource. Following the first link, you'll do something like this:

public class DataContextProxy : FrameworkElement
{
    public DataContextProxy()
    {
        this.Loaded += new RoutedEventHandler(DataContextProxy_Loaded);
    }

    void DataContextProxy_Loaded(object sender, RoutedEventArgs e)
    {
        Binding binding = new Binding();
        if (!String.IsNullOrEmpty(BindingPropertyName))
        {
            binding.Path = new PropertyPath(BindingPropertyName);
        }
        binding.Source = this.DataContext;
        binding.Mode = BindingMode;
        this.SetBinding(DataContextProxy.DataSourceProperty, binding);             
    }

    public Object DataSource
    {
        get { return (Object)GetValue(DataSourceProperty); }
        set { SetValue(DataSourceProperty, value); }
    }

    public static readonly DependencyProperty DataSourceProperty =
        DependencyProperty.Register("DataSource", typeof(Object), typeof(DataContextProxy), null);


    public string BindingPropertyName { get; set; }

    public BindingMode BindingMode { get; set; }

}

You should use public access modifier for _easingType

public List<string> _easingType = new List<string>(Enum.GetNames(typeof(EasingType)).ToArray());

In MainPage.xaml

<Page.Resources>        
    <local:DataContextProxy x:Key="DataContextProxy" />
    <ControlTemplate x:Key="BlurEditFlyout">
        ....
        <ComboBox ItemsSource="{Binding Source={StaticResource DataContextProxy}, Path=DataSource._easingType}" />
        ....
    <ControlTemplate x:Key="BlurEditFlyout">
</Page.Resources>
...

Upvotes: 2

Sunteen Wu
Sunteen Wu

Reputation: 10627

How to Bind/Set ItemsSource of ComboBox in ControlTemplate?

I'm not sure if you have deep reasons for asking this question, but directly to reply this question, we could just set the string list _esaingType as the value of DataContext property and binding it. For example:

XAML

<Page.Resources>
    <ControlTemplate TargetType="FlyoutPresenter"  x:Key="BlurEditFlyout" >
      ...                   
                <ComboBox ItemsSource="{Binding}" />
      ...
    </ControlTemplate>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">  
    <Button>
        <Button.Flyout>
            <Flyout>
                <Flyout.FlyoutPresenterStyle>
                    <Style TargetType="FlyoutPresenter">
                        <Setter Property="ScrollViewer.HorizontalScrollMode" Value="Disabled" />
                        <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
                        <Setter Property="Template" Value="{StaticResource BlurEditFlyout}">                                
                        </Setter>
                    </Style>
                </Flyout.FlyoutPresenterStyle>
                <!--<ContentControl Template="{StaticResource BlurEditFlyout}"/>-->
            </Flyout>
        </Button.Flyout>
        <SymbolIcon Symbol="Edit"/>
    </Button> 
</Grid>

Code behind

List<string> _easingType = new List<string>();  
public MainPage()
{
   this.InitializeComponent();
   _easingType.Add("test2");
   _easingType.Add("test1");
   this.DataContext = _easingType;
}

Any concerns on this way or any issues when using this on your side please kindly tell me I will follow up in time. More details please reference Data binding in depth.

Upvotes: 0

Related Questions