I'm using the LoopingSelector as shown in this tutorial: WP7-LoopingSelector-in-depth--Part1. I just copied their XAML and C# code. I modified the XAML a bit to fit my layout but it's still similar to their tutorial though.
Here is my XAML code where I put the LoopingSelector:
<Grid>
<StackPanel Grid.Row="2">
<TextBlock Text="Countdown Time" HorizontalAlignment="Center"
FontSize="28" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<toolkitPrimitives:LoopingSelector x:Name="hSelector"
ItemMargin="2,3,3,2" ItemSize="100,100" />
<TextBlock Text=":" VerticalAlignment="Center" FontSize="64"
FontFamily="{StaticResource Digital7}"/>
<toolkitPrimitives:LoopingSelector x:Name="mSelector"
ItemMargin="2,3,3,2" ItemSize="100,100" />
<TextBlock Text="'" VerticalAlignment="Center" FontSize="64"
FontFamily="{StaticResource Digital7}"/>
<toolkitPrimitives:LoopingSelector x:Name="sSelector"
ItemMargin="2,3,3,2" ItemSize="100,100" />
</StackPanel>
</StackPanel>
</Grid>
where toolkitPrimitives is defined as:
xmlns:toolkitPrimitives="clr-namespace:Microsoft.Phone.Controls.Primitives;assembly=Microsoft.Phone.Controls.Toolkit"
And here is what I did in the code behind:
this.hSelector.DataSource = new IntLoopingDataSource()
{
MinValue = 0,
MaxValue = 23,
SelectedItem = 0
};
this.mSelector.DataSource = new IntLoopingDataSource()
{
MinValue = 0,
MaxValue = 59,
SelectedItem = 1
};
this.sSelector.DataSource = new IntLoopingDataSource()
{
MinValue = 0,
MaxValue = 59,
SelectedItem = 0
};
I would have used TimePicker instead however it doesn't support picking Second. I need to pick Hour, Minute, and Second.
You need to set Width and Height and ItemSize on the looping selector. This control doesn't handle cases without an absolute size very well. That's why it doesn't work in a StackPanel.
StackPanels provide an infinite width and height.
Normally controls are supposed to handle those cases, but being a primitive control, they've made the assumption that those values will be set.
Through some experiments, I found out that, for some unknown reasons, LoopingSelector doesn't like StackPanel at all. If you want to have many LoopingSelector, the best way to achieve it is making a grid.
Here is my modified XAML:
<Grid>
<StackPanel Grid.Row="2">
<TextBlock Text="Countdown Time" HorizontalAlignment="Center" FontSize="28" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="0.1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="0.1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<toolkitPrimitives:LoopingSelector Grid.Column="0" x:Name="hSelector" ItemMargin="2,3,3,2" ItemSize="100,100" Height="300"/>
<TextBlock Grid.Column="1" Text=":" VerticalAlignment="Center" FontSize="64" FontFamily="{StaticResource Digital7}"/>
<toolkitPrimitives:LoopingSelector Grid.Column="2" x:Name="mSelector" ItemMargin="2,3,3,2" ItemSize="100,100" Height="300"/>
<TextBlock Grid.Column="3" Text="'" VerticalAlignment="Center" FontSize="64" FontFamily="{StaticResource Digital7}" />
<toolkitPrimitives:LoopingSelector Grid.Column="4" x:Name="sSelector" ItemMargin="2,3,3,2" ItemSize="100,100" Height="300"/>
</Grid>
</StackPanel>
</Grid>
Feel free to correct me if I'm wrong.
p.s. for someone who's familiar with StackOverflow, please help me format those XAML in my post because I don't know how to format it correctly.
Related
My goal is to save a GridSplitter position for later recall. The splitter is inside a Grid control that has three columns defined thusly:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding GridPanelWidth, Mode=TwoWay}" />
<ColumnDefinition Width="3" /> <!--splitter itself is in this column-->
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
The property GridPanelWidth is defined this way in the view model:
private GridLength _gridPanelWidth = new GridLength(1, GridUnitType.Star);
public GridLength GridPanelWidth
{
get { return _gridPanelWidth; }
set
{
if (_gridPanelWidth != value)
SetProperty(ref _gridPanelWidth, value, () => GridPanelWidth);
}
}
The problem I am having is that when the splitter is moved, the binding updates only the Double (Value) component of the bound property, but not the GridUnitType part of it.
Example: the property defaults to 1*. User drags the splitter and the value becomes 354*, instead of just 354. On restoring the value, then, it's huge (354 times, not 354 pixels).
Why is this happening, and what would you do about it?
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding GridPanelWidth, Mode=TwoWay}" />
<ColumnDefinition Width="4" />
<!--splitter itself is in this column-->
<ColumnDefinition x:Name="RightColumn" Width="2*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border
BorderBrush="Gray"
BorderThickness="1"
Grid.Column="0"
Grid.Row="0"
/>
<GridSplitter
Background="SteelBlue"
ResizeBehavior="PreviousAndNext"
ResizeDirection="Columns"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
ShowsPreview="False"
Grid.Column="1"
Grid.Row="0"
/>
<Border
BorderBrush="Gray"
BorderThickness="1"
Grid.Column="2"
Grid.Row="0"
/>
<StackPanel
Grid.Row="1"
Grid.ColumnSpan="3"
Grid.Column="0"
>
<TextBlock>
<Run>GridPanelWidth: </Run>
<Run Text="{Binding GridPanelWidth.Value, Mode=OneWay}" />
<Run Text="{Binding GridPanelWidth.GridUnitType, Mode=OneWay}" />
</TextBlock>
<TextBlock>
<Run>RightColumn.Width: </Run>
<Run Text="{Binding Width.Value, ElementName=RightColumn, Mode=OneWay}" />
<Run Text="{Binding Width.GridUnitType, ElementName=RightColumn, Mode=OneWay}" />
</TextBlock>
</StackPanel>
</Grid>
Screenshot 1:
Screenshot 2:
Screenshot 3:
Res ipsa loquitor, as far as I'm concerned, but just to be on the safe side:
Because the parent may be resized, the grid splitter changes the ratio between the two columns, while preserving the GridUnitType.Star for each one so that when the parent is resized, the ratio will naturally remain constant. This preserves the intent of the initial Width values in the XAML.
Width.Value for the left column turns out to be identical to the left Border's ActualWidth, and the same holds true for the right column. You'll have to grab both and save the ratio.
Update
I find Grid/GridSplitter a bit overengineered for everyday use when all I want is Yet Another Navigation Pane, so I recently wrote a SplitterControl that has two content properties and sets up the grid and splitter, with styling, in the template. I hadn't gotten around to making the split ratio persistent, so I did that just now.
What I did was rather painful because the control is configurable, and the code isn't all that great, but I can share if you're interested.
The business end is simple:
When a column resizes, set a flag to block recursion and
PaneRatio = _PART_ContentColumn.Width.Value / _PART_NavColumn.Width.Value;
When PaneRatio changes, if it wasn't set by the column size change handler
_PART_NavColumn.Width = new GridLength(1, GridUnitType.Star);
_PART_ContentColumn.Width = new GridLength(PaneRatio, GridUnitType.Star);
In practice, the navigator/content columns can be swapped, or they can be rows instead. Both of those are done by switching templates on a HeaderedContentControl that's a child of the split control template.
i am trying to refix the hamburger menu with some FontAwesome Icons, my way to do this is a ResourseDictionoary in my app. Now i want to bind the keyFontAwesomeUserString for the glyph bellow . My property in the object is Icon with type string. In my list the Icon var of x:DataType="local:MenuItem" has the values from my resoursedictionary.
<FontIcon Grid.Column="0" FontFamily="{StaticResource FontAwesomeFontFamily}" Glyph="{StaticResource FontAwesomeUserString}" Foreground="White" />
<TextBlock Grid.Column="1" Text="{x:Bind Name, Mode=OneWay}" TextWrapping="Wrap" FontSize="16" VerticalAlignment="Center" Foreground="White"/>
Please tell me if/how i can bind the ResourceKey property of StaticResourse.
Thank you
You can change the values of a resource dictionary by replacing them through code like:
Application.Current.Resources["FontAwesomeUserString"] = "&glyphCode";
Do not forget that StaticResource are only read when the page is created.
Depending when you are updating your dictionary, it could be enough but if you want your application to properly update itself when you are changing something in the resource dictionary, you will have to use ThemeResource.
You can get more details about ThemeResource here.
<FontIcon Grid.Column="0"
FontFamily="{ThemeResource FontAwesomeFontFamily}"
Glyph="{ThemeResource FontAwesomeUserString}"
Foreground="White" />
Update
If you are just trying to set the glyph/font family for all your items, a regular binding is enough:
<DataTemplate x:Key="DefaultTemplate" x:DataType="local:MenuItem">
<Grid Width="240" Height="48">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="48" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<FontIcon Grid.Column="0" FontFamily="{x:Bind FontFamily}" Glyph="{x:Bind Icon}" Foreground="White" />
<TextBlock Grid.Column="1" Text="{x:Bind Name, Mode=OneWay}" TextWrapping="Wrap" FontSize="16" VerticalAlignment="Center" Foreground="White"/>
</Grid>
</DataTemplate>
You just have to define the FontFamily and the Icon in your view mod.
el
You can have a look at the hamburger menu from the UWP toolkit documentation
I have changed the Background and Foreground Color of the MediaElement's MediaTransportControls using this solution UWP custom media controls not working
Now I want to
change the place of the 'TimeRemainingElement' and put it on the left of the Slider.
make the time show as 00:00 not 0:00:00
Is it possible to do that? Any idea how to do it?
1 more question: Is it possible to remove the "Cast to Device" icon/option from the MediaTransportControls?
Yeah, this is possible. As I've mentioned in my previous answer in UWP custom media controls not working, we can edit MediaTransportControls styles and templates to achieve what you want.
change the place of the 'TimeRemainingElement' and put it on the left of the Slider.
TimeRemainingElement is located in the Grid named "TimeTextGrid" which is in the second row of the Grid named "MediaTransportControls_Timeline_Grid". And the Slider named "ProgressSlider" is in the first row. So to put TimeRemainingElement on the left of the Slider, we can add a Grid in the first row, then remove TimeRemainingElement and ProgressSlider to the different columns of the new grid like:
<Grid x:Name="MyGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock x:Name="TimeRemainingElement"
Style="{StaticResource MediaTextBlockStyle}"
Text="00:00" />
<Slider x:Name="ProgressSlider"
Grid.Column="1"
Height="33"
MinWidth="80"
Margin="12,0"
VerticalAlignment="Center"
IsThumbToolTipEnabled="False"
Style="{StaticResource MediaSliderStyle}" />
<TextBlock x:Name="TimeElapsedElement"
Grid.Column="2"
Style="{StaticResource MediaTextBlockStyle}"
Text="00:00" />
</Grid>
And set the Visibility of TimeTextGrid to Collapsed like:
<Grid x:Name="TimeTextGrid"
Grid.Row="1"
Height="15"
Margin="12,0"
Visibility="Collapsed">
<!--<TextBlock x:Name="TimeElapsedElement"
Margin="0"
HorizontalAlignment="Left"
Style="{StaticResource MediaTextBlockStyle}"
Text="00:00" />
<TextBlock x:Name="TimeRemainingElement"
HorizontalAlignment="Right"
Style="{StaticResource MediaTextBlockStyle}"
Text="00:00" />-->
</Grid>
Here we can't delete TimeTextGrid. Missing TimeTextGrid would cause exception is some scenarios.
make the time show as 00:00 not 0:00:00
Changing the format of elapsed and remaining time is not easy. They are set in code-behind, just editing properties of TimeElapsedElement or TimeRemainingElement won't work. And I'm not sure why you need them show as "00:00". What if the media's duration is large than one hour? How to show a time that is "2:10:20"? I'd suggest you just use the original format, but if you do want to show it like "00:00", here is a workaround:
Firstly, we need to create a Format Converter to convert the time format like following:
public class TimeSpanFormatConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (!string.IsNullOrEmpty(value.ToString()))
{
var timeSpan = TimeSpan.Parse(value.ToString());
return timeSpan.ToString(#"mm\:ss");
}
else
{
return "00:00";
}
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
Then as the Text of TimeElapsedElement and TimeRemainingElement are set in code-behind, we can't use TimeSpanFormatConverter in TimeElapsedElement and TimeRemainingElement directly. So I add two TextBlocks and bind their Text property to the Text of TimeElapsedElement and TimeRemainingElement and use TimeSpanFormatConverter in my new TextBlock like:
<TextBlock x:Name="MyTimeRemaining"
Style="{StaticResource MediaTextBlockStyle}"
Text="{Binding Text,
Converter={StaticResource TimeSpanFormatConverter},
ElementName=TimeRemainingElement}" />
The StaticResource TimeSpanFormatConverter is defined as
<local:TimeSpanFormatConverter x:Key="TimeSpanFormatConverter" />
After this, I can hide TimeTextGrid and use my TextBlocks in MyGrid:
<Grid x:Name="MediaTransportControls_Timeline_Grid">
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid x:Name="MyGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock x:Name="MyTimeRemaining"
Style="{StaticResource MediaTextBlockStyle}"
Text="{Binding Text,
Converter={StaticResource TimeSpanFormatConverter},
ElementName=TimeRemainingElement}" />
<Slider x:Name="ProgressSlider"
Style="{StaticResource MediaSliderStyle}"
Grid.Column="1"
Height="33"
MinWidth="80"
Margin="12,0"
VerticalAlignment="Center"
IsThumbToolTipEnabled="False" />
<TextBlock x:Name="MyTimeElapsedElement"
Style="{StaticResource MediaTextBlockStyle}"
Grid.Column="2"
Text="{Binding Text,
Converter={StaticResource TimeSpanFormatConverter},
ElementName=TimeElapsedElement}" />
</Grid>
<ProgressBar x:Name="BufferingProgressBar"
Grid.ColumnSpan="3"
Height="4"
Margin="0,2,0,0"
VerticalAlignment="Top"
IsHitTestVisible="False"
IsIndeterminate="True"
Visibility="Collapsed" />
<Grid x:Name="TimeTextGrid"
Grid.Row="1"
Height="15"
Margin="12,0"
Visibility="Collapsed">
<TextBlock x:Name="TimeElapsedElement"
Style="{StaticResource MediaTextBlockStyle}"
Margin="0"
HorizontalAlignment="Left"
Text="00:00" />
<TextBlock x:Name="TimeRemainingElement"
Style="{StaticResource MediaTextBlockStyle}"
HorizontalAlignment="Right"
Text="00:00" />
</Grid>
</Grid>
Is it possible to remove the "Cast to Device" icon/option from the MediaTransportControls?
To remove the "Cast to Device" icon/option from the MediaTransportControls, we can just delete the AppBarButton named "CastButton" in "MediaControlsCommandBar" :
<!--<AppBarButton x:Name="CastButton"
Style="{StaticResource AppBarButtonStyle}"
MediaTransportControlsHelper.DropoutOrder="7">
<AppBarButton.Icon>
<FontIcon Glyph="" />
</AppBarButton.Icon>
</AppBarButton>-->
And finally, after these changes, the MediaTransportControls will look like:
I have defined two columns with separator like this:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="6"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<ScrollViewer Name="sideBar" Margin="{StaticResource SplitLeft}" SizeChanged="ScrollViewer_SizeChanged">
<StackPanel>
<TextBlock Text="LEFT CONTENT" Style="{StaticResource Heading2}" />
<TextBlock Text="" Name="ShowThings"/>
</StackPanel>
</ScrollViewer>
<GridSplitter Grid.Column="1" />
<ScrollViewer Name="ListPage" Grid.Column="2 " Margin="{StaticResource SplitRight}" SizeChanged="ScrollViewer_SizeChanged">
<StackPanel>
<TextBlock Text="RIGHT CONTENT" Style="{StaticResource Heading2}" />
<TextBlock Text="Content goes here" />
</StackPanel>
</ScrollViewer>
so the page is divided in 1:2 proportions. but if user wants to resize it, he can. I want to persist the modified width in app settings to be used for next launch.
on size change event I am storing the new width in settings,
Properties.Settings.Default[((ScrollViewer)sender).Name + "Width"] = e.NewSize.Width;
Properties.Settings.Default.Save();
and in window constructor loading the settings and setting the values.
sideBar.Width = (double)Properties.Settings.Default["sideBarWidth"];
but this does not work. can anyone help me identify the problem? I am sure this is a duplicate question, but I don't know what to search for.
It doesn't make sense to set the Width of your sideBar if it is depending on the size given in the Grid.ColumnDefinitions. Try to set the ColumnDefinition.Width:
// 0 = first column
grid.ColumnDefinitions[0].Width = new GridLength((double)Properties.Settings.Default["sideBarWidth"]);
I am trying to bind an image on the main window with a string (stored in another class) which represents the file path of the image I want to display.
But nothing shows up.
Here is my main window code xaml code:
<HierarchicalDataTemplate x:Key="categoryTemplate"
ItemsSource="{Binding Path=Items}"
ItemTemplate="{StaticResource animalTemplate}">
<Grid MouseEnter="DockPanel_MouseEnter" MouseLeave="DockPanel_MouseLeave">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="30" />
<ColumnDefinition Width="16" />
</Grid.ColumnDefinitions>
<Image HorizontalAlignment="Center" Source="{Binding Path=IconFilePath}" VerticalAlignment="Center" Width="16" Height="16" Grid.Column="0" />
<TextBlock Text="{Binding Path=Name}" Margin="5,0,0,0" FontWeight="Bold" FlowDirection="{Binding Path=FlowDirection}" FontSize="14" HorizontalAlignment="Stretch" Grid.Column="1" />
<Border CornerRadius="2" Background="Lavender" Grid.Column="2" Margin="0,0,5,0">
<TextBlock Text="30" Foreground="DodgerBlue" HorizontalAlignment="Center" FontWeight="Bold" FontSize="13" />
</Border>
<aea:MenuButton Margin="0,0,2,0" Opacity="0" HorizontalAlignment="Right" Grid.Column="3" SnapsToDevicePixels="False" Width="16" Height="16" DisplayStyle="Text" IsEnabled="True" IsDropDownOpen="False">
<aea:SplitButtonItem IsSelected="True" Visibility="Collapsed">
<Image HorizontalAlignment="Center" Source="Assets\FeedMenu.png" VerticalAlignment="Center"/>
</aea:SplitButtonItem>
<aea:SplitButtonItem Tag="{Binding Path=me}" Selected="Subscription_MarkAllAsRead">Mark all as Read</aea:SplitButtonItem>
<aea:SplitButtonItem Tag="{Binding Path=me}" Selected="Subscription_AddAllToFavorites">Add all to Favorites</aea:SplitButtonItem>
<aea:SplitButtonItem Tag="{Binding Path=me}" Selected="Subscription_ReadAllLater">Read all Later</aea:SplitButtonItem>
<aea:SplitButtonItem Tag="{Binding Path=me}" Selected="Subscription_OpenAllBrowser">Open all in browser</aea:SplitButtonItem>
</aea:MenuButton>
</Grid>
<!--<TextBlock Text="{Binding Path=Name}" FontWeight="Bold"/>-->
</HierarchicalDataTemplate>
Here is my other class:
public string IconFilePath { get; private set; }
public Subscription()
{
this.IconFilePath = #"C:\Users\Din\Din\Programming\Webs\Ended Projects\CodeCaged\Products\Read 360\Read 360\Read 360\bin\Release\feeds\1.ico";
}
You are binding relative to the DataContext so you need to make sure its an instance of that class. Also check for binding errors, not more to be said with this little context.
It is hard without a full code listing of how this control is setup (e.g. where and how is the DataContext set?, and how is the list of 'Items' populated?)
But on the surface it appears you're expecting to get both 'Name' and 'IconFilePath' from an Items element, so to confirm the Subscription Class defines both IconFilePath and Name?
A tool like Snoop can automatically display binding errors in a running applications visual tree; and I would expect it to list such in this case.
Also to reduce possible headaches (and this may well be the issue) it may be worth mentioning INotifyPropertyChanged for your data class. Property changes on your data class will not automatically progate otherwise.