Search code examples
c#mvvmuwpcommandbar

How can I dynamically change the Source of an Image within a CommandBar?


After searching for one day through the depth of the Internet, I try to ask you directly...

I wrote a Windows 10 UWP App in C#. I would like to Show the strength of the wifi Connection. I have several Images to show this. The wifi strength should be shown in the TopAppBar.

I used MVVM to set the Image Source. It works fine for an Image within a UserControl but I am not able to show the Image in the CommandBar.

I have an Event that gives me the Uri ("Picture") of the actual Image.

    private void WiFiInformationUpdated(object sender, WiFiInformationEventArgs args)
    {
        if (args.SSID != _viewModel.WifiInformationData.SSID)
        {
            _viewModel.WifiInformationData.SSID = args.SSID;
        }

        if (args.SignalBars != _viewModel.WifiInformationData.SignalBars)
        {
            _viewModel.WifiInformationData.SignalBars = args.SignalBars;
        }

        if(args.Picture != null)
        {
            Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,() =>
            {
                var pic = new BitmapImage(args.Picture);
                _viewModel.WifiInformationData.Picture = pic;
            }
            );
        }
    }

this is where it works fine within the UserControl:

<UserControl.DataContext>
    <Binding Path="Main" Source="{StaticResource Locator}"/>
</UserControl.DataContext>
<Image Source="{Binding WifiInformationData.Picture}" Grid.Row="1" Grid.Column="2" DataContextChanged="Image_DataContextChanged"/>

and this is the problematic Scene:

<Page.DataContext>
    <Binding Path="Main" Source="{StaticResource Locator}"/>
</Page.DataContext>
<Page.TopAppBar>
    <CommandBar HorizontalContentAlignment="Center" IsOpen="True" IsSticky="True" CompositeMode="Inherit">
        <CommandBar.ContentTemplate>
            <DataTemplate>
                <RelativePanel VerticalAlignment="Stretch" Width="200" >
                    <Image Source="{Binding Main.WifiInformationData.Picture, Source={StaticResource Locator}}" Width="20" RelativePanel.Below="tbPercentWifi" DataContextChanged="Image_DataContextChanged"/>
                </RelativePanel>
            </DataTemplate>
        </CommandBar.ContentTemplate>                        
    </CommandBar>
</Page.TopAppBar>

any suggestions please?


Solution

  • the solution is:

    DataTemplate Access Problems... fixed by:

    public static class DataTemplateObjects
    {
        public static DependencyObject FindChildControl<T>(DependencyObject control, string ctrlName)
        {
            int childNumber = VisualTreeHelper.GetChildrenCount(control);
            for (int i = 0; i < childNumber; i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(control, i);
                FrameworkElement fe = child as FrameworkElement;
                // Not a framework element or is null
                if (fe == null) return null;
    
                if (child is T && fe.Name == ctrlName)
                {
                    // Found the control so return
                    return child;
                }
                else
                {
                    // Not found it - search children
                    DependencyObject nextLevel = FindChildControl<T>(child, ctrlName);
                    if (nextLevel != null)
                        return nextLevel;
                }
            }
            return null;
        }
    }
    

    and then in my Event set the source of the Image:

        private void WiFiInformationUpdated(object sender, WiFiInformationEventArgs args)
        {
            if (args.SSID != _viewModel.WifiInformationData.SSID)
            {
                _viewModel.WifiInformationData.SSID = args.SSID;
            }
    
            if (args.SignalBars != _viewModel.WifiInformationData.SignalBars)
            {
                _viewModel.WifiInformationData.SignalBars = args.SignalBars;
            }
    
            if(args.Picture != null)
            {
                Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,() =>
                {
                    var pic = new BitmapImage(args.Picture);
                    _viewModel.WifiInformationData.Picture = pic;
                    Image img = DataTemplateObjects.FindChildControl<Image>(commandBar, "imgWifi") as Image;
                    if (img == null) return;
                    img.Source = pic;
                });
            }
        }