I have a Grid Layout with 7 elements in row. I want to move last 4 elements from first row to second if windowScreenWidth less than X. I already added a group and states.
If i use <Setter Target="el4.Grid.Row" Value="1"/> or <Setter Target="el4" Property="Grid.Row" Value="1"/> xaml throw exception.
Are there any way to make what i want?
The right XAML code is: Target="el4.(Grid.Row)" Value="1"/>
A bit late, but might help other people. Because the solution given wasn't the best (using if instead of style and states).
Found some workaround:
void WindowSizeChanged(object sender, SizeChangedEventArgs e)
{
double width = e.NewSize.Width;
if(width < 641)
{
el4.SetValue(Grid.RowProperty, 1);
el4.SetValue(Grid.ColumnProperty, 0);
}
else
{
el4.SetValue(Grid.RowProperty, 0);
el4.SetValue(Grid.ColumnProperty, 3);
}
}
public MainPage()
{
SizeChanged += WindowSizeChanged;
this.InitializeComponent();
}
Related
I am trying to hide last Grid column. I'm trying to do it with DataTrigger, this is how my trigger looks like:
<ResourceDictionary>
<Style x:Key="HideLastVerticalLine" TargetType="BoxView">
<Style.Triggers>
<DataTrigger
Binding="{Binding Items, Path=Items.LastOrDefault}"
TargetType="BoxView"
Value="{Binding Items.Length}">
<Setter Property="IsVisible" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
<BoxView Style="{StaticResource HideLastVerticalLine}" Grid.Column="1" HeightRequest="100" WidthRequest="1" BackgroundColor="Black"/>
I'm applying this DataTrigger to a BoxView, which contains a vertical line separator (I want something as Trim(), just to remove last separator line.
How can I do it?
You can use a DataTemplateSelector to achieve this.
The sample is here.
Create two DataTemplates, one for LastViewCell and one for other ViewCells:
public class PersonDataTemplateSelector : DataTemplateSelector
{
public DataTemplate NormalTemplate { get; set; }
public DataTemplate LastCellTemplate { get; set; }
protected override DataTemplate OnSelectTemplate (object item, BindableObject container)
{
var lastItem = Items.LastOrDefault();
return lastItem = item ? LastCellTemplate : NormalTemplate;
}
}
Choose to use which DataTemplate by checking if the item is last Item.
Create Bindable Layout.
Create separate template selector class.
The class used to populate the bindable layout itemsource must have new property isLast bool.
Update the list with last element as true.
Now Bind this new list with the bindable layout you are using on the view.
Don’t forget to add your templateselector on resource dictionary of that page.
For updating last item in list to isLast = true use.
int index = 0;
foreach (var item in list) // here updating last element of list islast =true
{
item.IsLast = (index == list.Count - 1);
index++;
}
Suppose I am making a simple UWP application which navigates through several pages. I would like to have a common background for all pages, depending on which background a user has selected from the Settings page.
I have a SettingsPage.xaml with a comboBox (and Grid Background that needs to change):
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ComboBox Name="ColourSelect" SelectionChanged="ComboBox_SelectionChanged">
<ComboBoxItem Name="Red">Red</ComboBoxItem>
<ComboBoxItem Name="Green">Green</ComboBoxItem>
<ComboBoxItem Name="Blue">Blue</ComboBoxItem>
</ComboBox>
</Grid>
Which interfaces with my SettingsPage.xaml.cs file:
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Change background
if (Red.IsSelected) { } // Change to Red.png
else if (Green.IsSelected) { } // Change to Green.png
else if (Blue.IsSelected) { } // Change to Blue.png
}
I have set up my App.xaml to contain a background resource, but I'm not sure how to bind it to the C# in Settings.xaml.cs.
<Application.Resources>
<Style TargetType="Grid" x:Key="CommonBackground">
<Setter Property="Background" Value="{ <!-- Some image. How to bind? --> }"
</Style>
</Application.Resources>
What should I return to bind the user decision to the Application resources?
Thank you in advance!
This requires few changes in different pieces of application. Follow my steps.
In this case I a am creating two Resources. One that will maintain the Settings Combobox Colour Scheme. Second one is BitMapImage in Resource.
So my Application.Resource will look something like below.
<Application.Resources>
<image:BitmapImage x:Key="BackgroundSource" UriSource="ms-appx:///Assets/Red.png" />
<x:String x:Key="BackgroundBrush">Red</x:String>
</Application.Resources>
Make sure you are adding xmlns:image="using:Windows.UI.Xaml.Media.Imaging" in your App.xaml.
Now Create a Static Method inside App.xaml.cs that will be used to update Background to the Page during Run time. It should be something like below.
public static void UpdateBGColors(string Color)
{
switch (Color)
{
case "Red":
Current.Resources["BackgroundSource"] = "ms-appx:///Assets/Red.png";
break;
case "Green":
Current.Resources["BackgroundSource"] = "ms-appx:///Assets/Green.png";
break;
case "Blue":
Current.Resources["BackgroundSource"] = "ms-appx:///Assets/Blue.png";
break;
default:
Current.Resources["BackgroundSource"] = "ms-appx:///Assets/Red.png";
break;
}
}
Now Your combobox_SelectionChanged should look like below.
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ComboBox cb = sender as ComboBox;
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
localSettings.Values["BackgroundBrush"] = (cb.SelectedValue as ComboBoxItem).Content;
App.UpdateBGColors((cb.SelectedValue as ComboBoxItem).Content.ToString());
}
Now you need to wire up the Background of each page to the Resource BackgroundSource. So anywhere you want the background to be set based on settings add below lines of code
<Grid>
<Grid.Background>
<ImageBrush ImageSource="{StaticResource BackgroundSource}" />
</Grid.Background>
......
</Grid>
At this point, if you change the setting in setting page and if you navigate back to original page that you came into setting page, The background should be set automatically to whatever you selected in Settings.
But you also want to make sure the same background is loaded when the app is opened next time. To do that in App.xaml.cs, Add below lines in the beginning of OnLaunched Event.
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
if (localSettings.Values["BackgroundBrush"] != null)
{
UpdateBGColors(localSettings.Values["BackgroundBrush"].ToString());
}
Since in settings page, you are saving BackgroundBrush Everytime you change the Combobox Item, Whenever your app is loading, Based on the BackgroundBrush BackgroundSource will be assigned to correct Uri and will be used as Page Backhground.
Full Repo is available Here
Good Luck.
[Update] You can use this, and after save your settings.
SettingsPage.xaml
<Grid>
<Grid.Background>
<ImageBrush x:Name="colorImage" Stretch="UniformToFill"/>
</Grid.Background>
<ComboBox Name="ColourSelect" SelectionChanged="ComboBox_SelectionChanged">
<ComboBoxItem Name="Red">Red</ComboBoxItem>
<ComboBoxItem Name="Green">Green</ComboBoxItem>
<ComboBoxItem Name="Blue">Blue</ComboBoxItem>
</ComboBox>
</Grid>
SettingsPage.xaml.cs
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (Red.IsSelected)
{
ChangeColorImage("ms-appx:///Assets/Red.png");
}
else if (Green.IsSelected)
{
ChangeColorImage("ms-appx:///Assets/Green.png");
}
else if (Blue.IsSelected)
{
ChangeColorImage("ms-appx:///Assets/Blue.png");
}
}
private void ChangeColorImage(string imageUrl)
{
// using Windows.UI.Xaml.Media.Imaging;
BitmapImage imageSource = new BitmapImage(new Uri(imageUrl));
colorImage.ImageSource = imageSource;
}
We have a UWP app using Template10. There is a textblock and textbox which show a discount. We wish to hide the textblock when ViewModel.Discount is null.
In App.xaml we have defined a converter
<T10Converters:ValueWhenConverter x:Key="HideWhenNullConverter" When="{x:Null}">
<T10Converters:ValueWhenConverter.Value>
<Visibility>Collapsed</Visibility>
</T10Converters:ValueWhenConverter.Value>
<T10Converters:ValueWhenConverter.Otherwise>
<Visibility>Visible</Visibility>
</T10Converters:ValueWhenConverter.Otherwise>
</T10Converters:ValueWhenConverter>
In the View we set the visibility of the TextBlock
Visibility="{x:Bind ViewModel.Discount, Converter={StaticResource HideWhenNullConverter}}"
In the ViewModel:
public class ViewModel : ViewModelBase
{
decimal? _Discount = default(decimal?);
public decimal? Discount
{
get
{
return _Discount;
}
set
{
if (value == 0) value = null;
Set(ref _Discount, value);
}
}
However the textblock is always visible even if the value of ViewModel.Discount is null. How do we hide the textblock when ViewModel.Discount is null
As I've tried with Template10's source it should work. I suspect that you are just missing redefinition of Mode with x:Bind, which as default is OneTime. Try like this:
Visibility="{x:Bind ViewModel.Discount, Mode=OneWay, Converter={StaticResource HideWhenNullConverter}}"
Adapting an project to Template10, I go into inherited styles in App.xaml are crashing.
It looks like Template10, doesn´t support inherited or extended styles. I was trying to extend SubTitleStyle from TitleStyle but I get an COM exceptions on GetXamlType in XamlTypeInfo.g.cs
My App.xaml.cs
sealed partial class App : BootStrapper
{
public App() { InitializeComponent(); }
public override async Task OnStartAsync(StartKind startKind, IActivatedEventArgs args)
{
NavigationService.Navigate(typeof(ShellView))
await Task.CompletedTask;
}
}
My App.xaml
<Style x:Key="TitleStyle" TargetType="TextBlock">
<Setter Property="Foreground" Value="{StaticResource TextTitleForeground}"/>
<Setter Property="FontSize" Value="26"/>
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="FontWeight" Value="Medium"/>
</Style>
<Style x:Key="SubTitleStyle" TargetType="TextBlock" BasedOn="{StaticResource TitleStyle}">
<Setter Property="Foreground" Value="{StaticResource TextForeground}"/>
<Setter Property="FontSize" Value="20"/>
</Style>
Exception info:
Error HRESULT E_FAIL has been returned from a call to a COM component.
at System.Runtime.InteropServices.WindowsRuntime.IIterator`1.MoveNext()
at System.Runtime.InteropServices.WindowsRuntime.IteratorToEnumeratorAdapter`1.MoveNext()
at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
at Template10.Common.BootStrapper.<InitializeFrameAsync>d__77.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Template10.Common.BootStrapper.<InternalLaunchAsync>d__53.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__6_0(Object state)
at System.Threading.WinRTSynchronizationContext.Invoker.InvokeCore()
This was deeply confounding to me. I was easily able to reproduce this. And, then, I was easily able to reproduce this without a reference to Template 10. The offending code is this block in T10:
// title
foreach (var resource in Application.Current.Resources
.Where(x => x.Key.Equals(typeof(Controls.CustomTitleBar))))
{
var control = new Controls.CustomTitleBar();
control.Style = resource.Value as Style;
}
You could simplify it to this:
var a = Application.Current.Resources.ToArray();
Placed in the OnLaunched of any app's Application. Boom. The error itself comes when we are attempting to access the resource collection but only when a BasedOn style has been added to the resources.
After sitting down with the platform team to try and vindicate Template 10, everyone around the table started scratching their heads. And, that's when I realized #dachibox, you have discovered a genuine bug in the XAML platform.
Here's the only current workaround until we update Template 10.
<Page.Resources>
<ResourceDictionary Source="..\Styles\Custom.xaml" />
</Page.Resources>
What I mean is, you do the work in the page instead of in App. So, how will we fix Template 10 without the XAML platform getting fixed? Take a look at this wonky code we will be using in Bootstrapper:
int count = Application.Current.Resources.Count;
foreach (var resource in Application.Current.Resources)
{
var k = resource.Key;
if (k == typeof(Controls.CustomTitleBar))
{
var s = resource.Value as Style;
var t = new Controls.CustomTitleBar();
t.Style = s;
}
count--;
if (count == 0) break;
}
The error, at least, is in the iterator's count property which seems to increment instead of decrement as you iterate through it. Crazy huh? Turns out, this iteration path is not a common use case. But, that does not matter now, we've raised the flag thanks to your question here.
I'll update Template 10 with the fix sometime this week.
Best of luck, Jerry
Previously I ported ExpanderView from Windows Phone toolkit to WinRT ExpanderRT, just to notice now that if you have two ExpanderView controls inside a StackPanel or ListView and you want the first expanderView to be expanded from the beginning by setting the IsExpanded property to True, then first expanderView will overlay the second one.
Here is an example:-
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel>
<local:ExpanderControl
IsExpanded="True"
Expander="This is the expander">
<local:ExpanderControl.Items>
<Button Content="Yes"/>
<Button Content="No"/>
</local:ExpanderControl.Items>
</local:ExpanderControl>
<local:ExpanderControl
IsExpanded="False"
Expander="This is the expander">
<ListViewItem>
<StackPanel Orientation="Horizontal">
<Button Content="yes"/>
<Button Content="no"/>
</StackPanel>
</ListViewItem>
</local:ExpanderControl>
</StackPanel>
</Grid>
After few hours trying to debug the ExpanderView control code i found out that this code is firing 4 times
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
{
if (_presenter == null) return;
var parent = _presenter.GetParentByType<ExpanderControl>();
var gt = parent.TransformToVisual(_presenter);
var childToParentCoordinates = gt.TransformPoint(new Point(0, 0));
_presenter.Width = parent.RenderSize.Width + childToParentCoordinates.X;
}
private void OnPresenterSizeChanged(object sender, SizeChangedEventArgs e)
{
if (null != _itemsCanvas && null != _presenter && IsExpanded)
{
_itemsCanvas.Height = _presenter.DesiredSize.Height;
}
}
During the first 2 times, the _itemsCanvas has a height of 0. While the third time it has a height of 64 just to be overwriten to 0 by the forth time.
I have not find any reason why this is happening. Anyone here can help?
I have faced similar issues after porting Expander from windows phone toolkit.
To fix this issue, I modified OnPresenterSizeChanged logic
private void OnPresenterSizeChanged(object sender, SizeChangedEventArgs e)
{
if (null != _itemsCanvas && null != _presenter && IsExpanded)
{
if (double.IsNaN(_itemsCanvas.Height))
{
VisualStateManager.GoToState(this, CollapsedState, false);
UpdateVisualState(true);
}
else
{
// Already expanded, so we need to update the height of the canvas directly.
_itemsCanvas.Height = _presenter.DesiredSize.Height;
}
}
}
What is different here is that I check if the item canvas has been rendered before or not based on checking if it's height is Nan, if that's the case then I change visual state to collapse without transition then I call UpdateVisualState(true). else I just update the render height of canvas.
The issue was that the first time UpdateVisualState was called, the content presnter was null.