WPF dla zaawansowanych (kwiecień 2021)

Seria pytań uczestników, które pojawiły się podczas szkolenia WPF dla zaawansowanych realizowanego w dniach 26-30.04.2021 r.


Czy można zmienić kolor tła w designerze?

Tak, można to uzyskać za pomocą nieudokumentowanej funkcji:



UserControl
<d:DesignerProperties.DesignStyle>
        <Style TargetType="UserControl">
            <Setter Property="Background" Value="DarkGray" />
        </Style>
    </d:DesignerProperties.DesignStyle>
Page
<d:DesignerProperties.DesignStyle>
        <Style TargetType="Page">
            <Setter Property="Background" Value="DarkBlue" />
        </Style>
    </d:DesignerProperties.DesignStyle>

 

Styl taki można przenieść do zasobów i skorzystać z niego na UserControl:

  
<Style x:Key="MyDesignUserControlStyle" TargetType="UserControl">
        <Setter Property="Background" Value="DarkGreen" />
        <Setter Property="Foreground" Value="White" />
    </Style>
<UserControl
    d:DesignHeight="450"
    d:DesignStyle="{StaticResource MyDesignUserControlStyle}"
    d:DesignWidth="800"
    mc:Ignorable="d">

W jaki sposób zbindować do kontrolki WebBrowser lub WebView2 adres strony?

Niestety właściwość Source nie jest typu DependencyProperty i przez to nie można jej powiązać za pomocą Bindingu. Ale jak sposób na obejście tego problemu...

Należy utworzyć Attached Property:



public static class WebView2AttachedProperty
    {
        public static readonly DependencyProperty BindableSourceProperty =
            DependencyProperty.RegisterAttached("BindableSource",
                typeof(string), typeof(WebView2AttachedProperty), new PropertyMetadata(null, BindableSourcePropertyChanged));

        private static void BindableSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var webBrowser = (WebView2)d;

            webBrowser.Source = new Uri((string)e.NewValue);
        }

        public static string GetBindableSource(DependencyObject obj)
        {
            return (string)obj.GetValue(BindableSourceProperty);
        }

        public static void SetBindableSource(DependencyObject obj, string value)
        {
            obj.SetValue(BindableSourceProperty, value);
        }
    }

 

1. Tworzymy przekierowanie zdarzenia Drop na komendę:



<wv2:WebView2 ap:WebView2AttachedProperty.BindableSource="{Binding Url}" />

 

W jaki sposób zaimplementować Drag and Drop pomiędzy listami zgodnie z MVVM?

1. Tworzymy przekierowanie zdarzenia Drop na komendę:



<ListBox   AllowDrop="True">
   <i:Interaction.Triggers>
       <i:EventTrigger EventName="Drop">
                              <i:InvokeCommandAction
                                  Command="{Binding DropRemoveCustomerCommand}"
                                  EventArgsConverter="{c:DragEventArgsConverter}"
                                  PassEventArgsToCommand="True" />
                          </i:EventTrigger>
 </i:Interaction.Triggers>
</ListBox>

 

Podpinamy konwerter, który pobierze przeciągany obiekt modelu:


public class DragEventArgsConverter : MarkupExtension, IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            DragEventArgs e = (DragEventArgs)value;

            Customer customer = e.Data.GetData(typeof(Customer)) as Customer;

            return customer;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return this;
        }
    }
 

Tworzymy własne MarkupExtension do obsługi zdarzenia Move:


public class MouseMoveMarkupExtension : MarkupExtension
    {
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return new MouseEventHandler(OnMouseEventHandler);
        }

        private void OnMouseEventHandler(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                Selector selector = sender as Selector;  

                DragDrop.DoDragDrop(selector, selector.SelectedItem, DragDropEffects.Move);
            }
        }
    }
 

Podpinamy powyższą klasę pod zdarzenie MouseMove:



<ListBox   MouseMove="{me:MouseMoveMarkup}" >
</ListBox>