Domanda

I want to create some sort of filter, when user clicks the filter button from the app bar it will fire up a popup page with list picker in it. I've googled and tried quite a number of solutions but still cannot get it to work.

Here are my codes:

XAML (MainPageView.xaml)

<phone:PhoneApplicationPage.Resources>
      <DataTemplate x:Key="PivotContentTemplate">
            <phone:Pivot Margin="-12,0,0,0" Title="FOREX NEWS" Height="672">
                <phone:PivotItem Header="filter" FontFamily="{StaticResource PhoneFontFamilySemiLight}" FontSize="32">
                    <StackPanel Margin="12,0,0,0">
                        <toolkit:ListPicker Header="currencies" SelectionMode="Multiple"
                                            micro:Message.Attach="[Event SelectionChanged] = [Action OnCurrenciesChanged($eventArgs)]">
                            <sys:String>gbp</sys:String>
                            <sys:String>eur</sys:String>
                            <sys:String>usd</sys:String>
                        </toolkit:ListPicker>                        
                    </StackPanel>
                </phone:PivotItem>
            </phone:Pivot>
        </DataTemplate>
<phone:PhoneApplicationPage.Resources>

...

Still inside MainPageView.xaml

<bab:BindableAppBar Grid.Row="2" Mode="Minimized">
    <bab:BindableAppBarButton micro:Message.Attach="[Event Click] = [Action ShowFilter($view, $eventArgs]">

    </bab:BindableAppBarButton>
</bab:BindableAppBar>

MainPageViewModel.cs

public void ShowFilter(object sender, RoutedEventArgs e)
{
    var view= sender as MainPageView;

    CustomMessageBox messageBox = new CustomMessageBox()
    {
        ContentTemplate = (DataTemplate)view.Resources["PivotContentTemplate"],
        LeftButtonContent = "filter",
        RightButtonContent = "cancel",
        IsFullScreen = true // Pivots should always be full-screen.
    };

    messageBox.Dismissed += (s1, e1) =>
    {
        switch (e1.Result)
        {
            case CustomMessageBoxResult.LeftButton:
                // Do something.
                break;
            case CustomMessageBoxResult.RightButton:
                // Do something.
                break;
            case CustomMessageBoxResult.None:
                // Do something.
                break;
            default:
                break;
        }
    };

    messageBox.Show();
}

public void OnCurrenciesChanged(SelectionChangedEventArgs e)
{

}

For your information, I am using Caliburn.Micro and WP Toolkit for the CustomMessageBox and ListPicker.

I received exception No target found for method OnCurrenciesChanged. I only receive the exception when I after I select few items in the list picker and click any of the buttons to save the change. Another thing is that the OnCurrenciesChanged does not get triggered at all.

I think (based on what I read so far) whenever the CustomMessageBox get called, the datacontext its operating at is no longer pointing to the MainPageViewModel thus it could not find the method. But I am not sure how to actually do this.

More details: Exception happen after I click the left button (checkmark) exception_here

Updates So far I have try the following:

<StackPanel Margin="12,0,0,0" DataContext="{Binding DataContext, RelativeSource={RelativeSource TemplatedParent}}"> //also tried with Self

and I also added this when I instantiate messageBox

        var messageBox = new CustomMessageBox()
        {
            ContentTemplate = (DataTemplate)view.Resources["PivotContentTemplate"],
            DataContext = view.DataContext, // added this
            LeftButtonContent = "filter",
            RightButtonContent = "cancel",
            IsFullScreen = true
        }; 

The idea is that when the messsagebox is created, the datacontext will be the same as when the view is instantiated. However, it seems that the datacontext does not get inherited by the PickerList

È stato utile?

Soluzione

Ok so I managed to get this to work. The solution is not pretty and I think it beats the purpose of MVVM at the first place.

Based on http://wp.qmatteoq.com/first-steps-in-caliburn-micro-with-windows-phone-8-how-to-manage-different-datacontext/ , inside a template the DataContext will be different. So, I need to somehow tell ListPicker to use the correct DataContext.

The solution provided by link above doesn't work for me. I think it is because when ListPicker is called inside CustomMessageBox, MainPageViewModel is no longer available or it seems not to be able to find it as suggested by the exception. So as per above code example in the question, even if I set the correct DataContext to the CustomMessageBox, it does not get inherited somehow by the ListPicker.

Here is my solution:

     var messageBox = new CustomMessageBox()
        {
            Name = "FilterCustomMessageBox", // added this
            ContentTemplate = (DataTemplate)view.Resources["PivotContentTemplate"],
            DataContext = view.DataContext,
            LeftButtonContent = "filter",
            RightButtonContent = "cancel",
            IsFullScreen = true
        };

In the XAML, I edited to this

            <toolkit:ListPicker Header="currencies" SelectionMode="Multiple"
                                micro:Action.TargetWithoutContext="{Binding ElementName=FilterCustomMessageBox, Path=DataContext}"
                                micro:Message.Attach="[Event SelectionChanged] = [Action OnCurrenciesChanged($eventArgs)]">

It's ugly because both ViewModel and View need to explicitly know the Name. In WPF, you can just do something like this in the binding to inherit the DataContext of the parent/etc but this is not available for WP.

{Binding DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}}}

If anyone has better workaround, do let me know!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top