Trying to learn a fair bit about s and I got stuck on a particular subject. I want my buttons edited in size and alignment using a pre made style I have. An example:
<Button Style="{StaticResource ButtonFormat}">
</Button>
The button has a style saved in App.Xaml the style is written like this:
<Application.Resources>
<Style TargetType="Button" x:Key="ButtonFormat">
<Setter Property="Background" Value="#FF6E1400" />
<Setter Property="Margin" Value="5,5,5,5" />
</Style>
<Application.Resources>
Now, here is my dilemma:
I want to load another style that overwrites "ButtomFormat". I have been trying to experiment in VisualStatemanager to try and come up with the proper way of doing this but can't really find anything that explains enough for me on how to do it.
So in the visualstate such as below:
<VisualState x:Name="BigView" >
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="550" />
</VisualState.StateTriggers>
<VisualState.Setters>
<!--stuff goes here-->
<!--stuff goes here-->
</VisualState.Setters>
</VisualState>
I want to ooverwrite ButtonFormat with ButtonFormatBlue as such:
<Style TargetType="Button" x:Key="ButtonFormatBlue ">
<Setter Property="Background" Value="Blue" />
<Setter Property="Margin" Value="5,5,5,5" />
</Style>
I saw someone suggesting using C# instead of visualstatemanagers but I didn't properly understand that description, is it possible to load it from the visualstatetrigger as I want or am I looking at the wrong direction?
All aids are appreciated, thank you in advance!
You cannot override a resource, but you can change the Button's style property.
You first have to give the button a name:
<Button x:Name="MyButton" Style="{StaticResource ButtonFormat}">
</Button>
And now you can use the VisualStateManager to change the Style property:
<VisualState x:Name="BigView">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="550" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MyButton.Style"
Value="{StaticResource ButtonFormatBlue}" />
</VisualState.Setters>
</VisualState>
I saw someone suggesting using C# instead of visualstatemanagers but I didn't properly understand that description.
It means you can set a style to your Button manually in the code behind. For example, you can put your ButtonFormat and ButtonFormatBlue both in the App resource like this:
<Application.Resources>
<Style TargetType="Button" x:Key="ButtonFormat">
<Setter Property="Background" Value="#FF6E1400" />
<Setter Property="Margin" Value="5,5,5,5" />
</Style>
<Style TargetType="Button" x:Key="ButtonFormatBlue">
<Setter Property="Background" Value="Blue" />
<Setter Property="Margin" Value="5,5,5,5" />
</Style>
</Application.Resources>
Then your Button can be loaded with ButtonFormat style using StaticResource:
<Button x:Name="styleTestButton" Content="Style Sample" Style="{StaticResource ButtonFormat}"
VerticalAlignment="Bottom" Click="styleTestButton_Click" />
In the Button click event for example, you can change your Button's style as follows:
private void styleTestButton_Click(object sender, RoutedEventArgs e)
{
var ButtonFormatBlue = Application.Current.Resources.FirstOrDefault(r => r.Key.ToString() == "ButtonFormatBlue");
styleTestButton.Style = ButtonFormatBlue.Value as Style;
}
Or you can totally define a new style in the code behind and set this style to Button using C# in the code behind:
private void styleTestButton_Click(object sender, RoutedEventArgs e)
{
var dynamicStyle = new Style();
dynamicStyle.TargetType = typeof(Button);
dynamicStyle.Setters.Add(new Setter(BackgroundProperty, Colors.Blue));
dynamicStyle.Setters.Add(new Setter(MarginProperty, new Thickness(5, 5, 5, 5)));
styleTestButton.Style = dynamicStyle;
}
Need to know that as #MZetko said, we can't override a resource, this is why we created a new one.
is it possible to load it from the visualstatetrigger as I want or am I looking at the wrong direction?
Yes it's possible, but it's hard to tell whether you looked at the wrong direction, it depends on different scenarios. For example, if your UIElements are in the DataTemplate, then it doesn't work with StateTriggers, data binding is the best solution for this scenario. You can refer to the Remarks of VisualStateManager class, it shows perfect details of using VisualStateManager.
Related
I have correctly implemented LibVlcSharp in my Xamarin.Forms project.
using (var _libVLC = new LibVLC())
{
var media = new Media(_libVLC, _link, FromType.FromLocation);
myvideo.MediaPlayer = new MediaPlayer(media)
{
Fullscreen = true
};
myvideo.MediaPlayer.Play();
};
In my video player I stream video from google drive but sometimes it can happen that the media gives error and this error is shown:
Streaming works, there may be many reasons for the error but that's not what interests me.
I would like to understand how to intercept this error and customize this error label but I have not found anything in the documentation or online.
I also wanted to know if it was possible to change the style of the buttons, I found this property myvideo.PlaybackControls that has many other properties but I do not know if it is correct and how to apply it.
Thanks
There is ShowError method but no other details
private void ShowError()
{
var errorTextBlock = ErrorTextBlock;
if (errorTextBlock != null)
{
errorTextBlock.Text = string.Format(ResourceLoader.GetString("Error"), Manager.Get<StateManager>().MediaResourceLocator);
VisualStateManager.GoToState(this, ErrorState, true);
}
}
You can get more log by subscribing to LibVLC.Log event
I havent run code but I believe you can intercept errors with ErrorOccured event as below
var stateManager = Manager.Get<StateManager>();
stateManager.ErrorOccured += (sender, e) => ShowError();
That should give you what is causing the issue, if not you should raise an issue on libvlcsharp github
Looks like they have created PlayBackControls property bind to PlayBackControls of LibVLCSharp.Uno library PlayBackControls element and the icons are applied through this XAML
<ContentPresenter Grid.Row="1" Content="{TemplateBinding PlaybackControls}" />
You should be able to change it by binding as far as it matches PlayBackControls.Android.iOS
Have a look at
<Label Text="{TemplateBinding ErrorMessage}" Style="{TemplateBinding MessageStyle}"
IsVisible="{TemplateBinding ErrorMessage, Converter={StaticResource ObjectToBoolConverter}}" />
From https://code.videolan.org/videolan/LibVLCSharp/-/blob/3.x/LibVLCSharp.Forms/Shared/Themes/Generic.xaml. This is the base style provided by LibVLCSharp that you want to modify.
You can override the style by following this guide https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/styles/xaml/inheritance
In XAML, that could be
<Style x:Key="labelStyle" TargetType="Label" BasedOn="{StaticResource MessageStyle}">
<Setter Property="TextColor" Value="Teal" />
</Style>
I created a ticket to add more docs about this https://code.videolan.org/videolan/LibVLCSharp/-/issues/309
You can hide all items and add your controls.
<vlc:MediaPlayerElement x:Name="VideoView"
AbsoluteLayout.LayoutFlags="All"
EnableRendererDiscovery="False"
AbsoluteLayout.LayoutBounds="0,0,1,1">
<vlc:MediaPlayerElement.PlaybackControls>
<vlc:PlaybackControls IsVisible="true"
IsAspectRatioButtonVisible="True"
ShowAndHideAutomatically="True"
IsRewindButtonVisible="True"
IsCastButtonVisible="True"
IsLockButtonVisible="True"
IsSeekBarVisible="True"
IsSeekButtonVisible="True"
IsSeekEnabled="True"
IsTracksButtonVisible="True">
<vlc:PlaybackControls.RemainingTimeLabelStyle>
<Style TargetType="Label">
<Setter Property="IsVisible"
Value="false" />
</Style>
</vlc:PlaybackControls.RemainingTimeLabelStyle>
<vlc:PlaybackControls.MessageStyle>
<Style TargetType="Label">
<Setter Property="IsVisible"
Value="false" />
<Setter Property="TextColor" Value="Transparent"/>
<Setter Property="Text"
Value="0" />
</Style>
</vlc:PlaybackControls.MessageStyle>
<vlc:PlaybackControls.ElapsedTimeLabelStyle>
<Style TargetType="Label">
<Setter Property="IsVisible"
Value="false" />
</Style>
</vlc:PlaybackControls.ElapsedTimeLabelStyle>
</vlc:PlaybackControls>
</vlc:MediaPlayerElement.PlaybackControls>
</vlc:MediaPlayerElement>
I've written a WPF plugin for some off-the-shelf product, and in this plugin I've used a theme/style to change the minimal width of all buttons like so:
<Style TargetType="Button">
<Setter Property="MinWidth" Value="80" />
</Style>
In the newest version of said off-the-shelf product they migrated from winforms to WPF themselves. Now when my plugin is loaded the style that previously just affected my plugged-in forms now affects all buttons in the application. This renders most UI's unusable.
I know I can use dictionary key based resources to make this style specific to my buttons, but this means I have to change each and every button in my plugin by hand, as well as not forget to set the style of each button in the future (and other elements this problem applies to). There are other options to make the style specific to a set of buttons, as seen in Is it possible to set a style in XAML that selectively affects controls? But I'm looking for a way to let my style affect only those of my plugin (so a bit more coarse than talked about in the referenced question). This plugin consists of multiple windows/views (tied together with Caliburn.Micro).
Is there a way to easily scope a style to for instance an assembly or namespace? I'd really like to define my resources just once. Currently it's defined at the Application.Resources level, if there's one more appropriate I'd like to hear that too.
With a ResourceDictionary, we can set default style wich will be applied without define style in Xaml.
DictionayNew.xaml :
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Media="clr-namespace:System.Windows.Media;assembly=PresentationCore"
xmlns:System="clr-namespace:System;assembly=mscorlib">
<!-- default button -->
<Style TargetType="{x:Type Button}">
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="MinWidth" Value="80" />
</Style>
<!-- new button style -->
<Style x:Key="ActionButton" TargetType="{x:Type Button}">
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="MinWidth" Value="75" />
<Setter Property="Height" Value="23" />
</Style>
<!-- new button style based on previous style -->
<Style x:Key="BigActionButton"
BasedOn="{StaticResource ActionButton}"
TargetType="{x:Type Button}">
<Setter Property="MinWidth" Value="150" />
<Setter Property="Height" Value="30" />
</Style>
</ResourceDictionary>
In your Xaml, use the dictionary :
<Window x:Class="CheckDoublonImageBing.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="DictionaryNew.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
</Grid>
</Window>
Then, use Button as usual or with new style
<Button Content="Refresh" />
<Button Content="Delete selected" Style="{DynamicResource ActionButton}" />
With no style defined, button will have default style defined in the dictionary.
EDIT :
You can set merged dictionary by code like this :
ResourceDictionary myResourceDictionary = new ResourceDictionary();
myResourceDictionary.Source = new Uri("DictionayNew.xaml", UriKind.Relative);
Application.Current.Resources.MergedDictionaries.Add(myResourceDictionary);
You need to specify a Key for your Style and apply the Style to all your Buttons.
<Style TargetType="Button" x:Key="MyButtonStyle">
<Setter Property="MinWidth" Value="80" />
</Style>
<Button Style="{StaticResource MyButtonStyle}"/>
Without a Key the Style is used for all Buttons in the application (as you have already noticed).
App contain more than 30 buttons but there alignments are incorrect
my question is:
Is there any property for arranging all 30 button in fixed length and height?
If you want share same setting between all 30 buttons you should use Styles:
<Style TargetType="Button">
<Setter Property="Width" Value="20" />
</Style>
After you'll have all buttons with width 20. This is happening due to a concept called implicit styles. Any time you are specifying style without Key it will automatically apply it to all TargetTypes without explicitly defined style.
Have you tried using a Style to declare your Button dimensions? Try adding this into your Resources section:
<Window.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Height" Value="24" />
<Setter Property="Width" Value="150" />
</Style>
</Window.Resources>
This will affect all Buttons within scope of the Style, but you could change it to this...:
<Style x:Key="SizedButton" TargetType="{x:Type Button}">
<Setter Property="Height" Value="24" />
<Setter Property="Width" Value="150" />
</Style>
... and then explicitly assign the Style to each Button:
<Button Content="Something" Style="{StaticResource SizedButton}" />
I have a WPF button like so:
<Page.Resources>
<ImageBrush x:Key="black_pane_normal" ImageSource="/Images/TroubleShooting/black_pane_clear.png" />
</Page.Resources>
<Button x:Name="ButtonBlackPane" Background="{StaticResource black_pane_normal}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="157" Height="136" MouseEnter="ButtonBlackPane_MouseEnter" MouseLeave="ButtonBlackPane_MouseLeave" Click="ButtonBlackPane_Click" RenderTransformOrigin="0.533,0.281" Margin="189,199,0,0"/>
My C# code behind is:
BitmapSource _black_pane_yellow_border = Imaging.CreateBitmapSourceFromHBitmap(InstallerToolkit.Properties.Resources.black_pane_yellow.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
BitmapSource _black_pane_no_border = Imaging.CreateBitmapSourceFromHBitmap(InstallerToolkit.Properties.Resources.black_pane_clear.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
private void ButtonBlackPane_MouseEnter(object sender, MouseEventArgs e)
{
ButtonBlackPane.Background = new ImageBrush(_black_pane_yellow_border);
}
private void ButtonBlackPane_MouseLeave(object sender, MouseEventArgs e)
{
ButtonBlackPane.Background = new ImageBrush(_black_pane_no_border);
}
My first problem is that my image does not fill the whole button background, how do I get this to fill it?
My second problem is that when the mouse enters the button, the correct background image gets displayed for a moment and then the default gray button image shows and my image goes away, how can I solve this?
First, it's not a good practice to set first the background with a static resource and then use code to set it each time to a new ImageBrush object. Have a look at the FindResource method (http://msdn.microsoft.com/de-de/library/system.windows.frameworkelement.findresource(v=vs.110).aspx) to use your resources in code behind.
Second, you should use Styles and Triggers to modify the appearance of a control depending for example on the MouseOver-State. There is a property called IsMouseOver which you can use for that. Here is an example:
<Page.Resources>
<Style TargetType="Button" x:Key="myButtonStyle">
<Setter Property="Foreground" Value="Red" />
<Setter Property="FontSize" Value="12" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Foreground" Value="Blue" />
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="FontSize" Value="16" />
</Trigger>
</Style.Triggers>
</Style>
</Page.Resources>
<Button Width="200" Height="100" Style="{StaticResource myButtonStyle}">Hello, World!</Button>
Third, because of the default template of a WPF button, you cannot change directly the background of it when hovering with the mouse. This problem is discussed and solved here: How do you change Background for a Button MouseOver in WPF?
If you want to have more Information about styling WPF controls and how to use the default templates, have a look here: http://msdn.microsoft.com/en-us/library/aa970773.aspx
I'm new to WPF, but searching internet for some days I couldn't figure out my problem.
After I programmatically change Foreground property, IsMouseOver trigger doesn't work. Please be tolerant and thank in advance :)
<Style x:Key="ZizaMenuItem" TargetType="{x:Type Button}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="Margin" Value="5,0,5,0"/>
<Setter Property="Height" Value="30"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Label FontSize="14" Content="{TemplateBinding Content}" Name="ZizaMenuItemText" />
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="ZizaMenuItemText" Property="Foreground" Value="#ff0000"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<StackPanel Height="30" Name="ZizaMenu" Orientation="Horizontal" Margin="0,12,0,0" VerticalAlignment="Top">
<Label Content="ZIZA" FontSize="11" FontWeight="Bold" Foreground="Black" Height="25" Margin="20,0,10,0" />
<Button Name="ZizaMenuInteresting" Click="ZizaMenuItemClicked" Content="ИНТЕРЕСНОЕ" Style="{StaticResource ZizaMenuItem}" />
<Button Name="ZizaMenuBest" Click="ZizaMenuItemClicked" Content="ЛУЧШЕЕ" Style="{StaticResource ZizaMenuItem}" />
<Button Name="ZizaMenuAuto" Click="ZizaMenuItemClicked" Content="АВТО" Style="{StaticResource ZizaMenuItem}" />
</StackPanel>
private void ZizaMenuItemClicked(object sender, RoutedEventArgs e)
{
// get label object from template
Button zizaMenuItem = (Button)sender;
Label zizaMenuItemText = (Label)zizaMenuItem.Template.FindName("ZizaMenuItemText", zizaMenuItem);
// set Foreground color for all buttons in menu
foreach (var item in ZizaMenu.Children)
if (item is Button)
((Label)(item as Button).Template.FindName("ZizaMenuItemText", (item as Button))).Foreground = Brushes.Black;
// set desired color to clicked button label
zizaMenuItemText.Foreground = new SolidColorBrush(Color.FromRgb(102, 206, 245));
}
That is horrible code, do not mess with controls inside control templates, ever. Template.FindName is something only the control that is being templated should call internally to get its parts, and only those, everything else should be considered uncertain.
If you need to change a property template bind it, and then bind or set said property on the instance. In terms of precedence you need to make sure not to create a local value which overrides the triggers (that is what you did). You can use a Style and Setter on the Label to bind the default Foreground.
<Label.Style>
<Style TargetType="Label">
<Setter Property="Foreground" Value="{TemplateBinding Foreground}"/>
</Style>
</Label.Style>
Now you just need to set the Foreground of the Button itself, the Trigger should still internally have precedence over that Setter.
It has to do with dependency property value precedence. Local values have higher precedence than template triggers.
For more information read this: http://msdn.microsoft.com/en-us/library/ms743230.aspx