How to fill an Arc on an Arc other? - wpf

Currently, I have two Arcs but there are small borders of the wrong color (see black arrow) :
xaml:
<Window x:Class="WpfApplication9.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing">
<Grid Width="150" Height="150">
<ed:Arc
x:Name="BorderArc"
ArcThickness="15"
StrokeThickness="0"
ArcThicknessUnit="Pixel"
StartAngle="270"
EndAngle="45"
Fill="Red"
Stretch="None"
RenderTransformOrigin=".5 .5"
Width="150"
Height="150">
</ed:Arc>
<ed:Arc
x:Name="Border"
ArcThickness="15"
StrokeThickness="0"
ArcThicknessUnit="Pixel"
StartAngle="270"
EndAngle="30"
Fill="Gray"
Stretch="None"
RenderTransformOrigin=".5 .5"
Width="150"
Height="150">
</ed:Arc>
</Grid>
Please give me a solution for remove small red border (see black arrow)? Thanks for help me?

You could set the ArcThickness of the grey arc to 15.1, and see if that removes the red outline.
What happens if you give both arcs a white border of a single pixel?
Option 1: Modify the ViewModel
Could your ViewModel be modified to process the Arcs like this:
ArcViewModels = new List<SingleArcViewModel>();
for (var i = 0; i < Arcs.Count; i++)
{
if (i == 0)
{
ArcViewModels.Add(new SingleArcViewModel(Arcs[i].StartAngle, Arcs[i].EndAngle));
}
else
{
ArcViewModels.Add(new SingleArcViewModel(Arcs[i - 1].EndAngle, Arcs[i].EndAngle));
}
}
(I am assuming that the constructor takes StartAngle first, then EndAngle).
Where Arcs is your existing list of Arcs, and ArcViewModels is what you will bind your View to. It has the StartAngle of each arc set to the EndAngle of the previous one.
I've tried this in a simple application and it works OK, obviously you will have to make some modifications to your view model to process the arcs for binding to.
Option 2: Run the Arcs collection through an IValueConverter
You'll need to create a Converter class like this:
public class ArcCollectionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var arcsCollection = value as ArcViewModel[];
if (arcsCollection == null)
return value;
var result = new List<ArcViewModel>();
for (var i = 0; i < arcsCollection.Count(); i++)
{
if (i == 0)
{
result.Add(new SingleArcViewModel(arcsCollection[i].StartAngle, arcsCollection[i].EndAngle));
}
else
{
result.Add(new SingleArcViewModel(arcsCollection[i - 1].EndAngle, arcsCollection[i].EndAngle));
}
}
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then add the following to the references in your View:
xmlns:cc="clr-namespace:LocalExperiment.Models"
The resources:
<Window.Resources>
<cc:ArcCollectionConverter x:Key="ArcCollectionConverter" />
</Window.Resources>
And use the converter wherever you are binding to the arcs collection:
<ItemsControl ItemsSource="{Binding MyArcs, Converter={StaticResource ArcCollectionConverter}}"></ItemsControl>
You may need to modify some of the types to get it to work with your ViewModel, but hopefully this will get you started.

You have one arc on top of another. just modify them to not overlap:
<!-- I have ommited some properties -->
<ed:Arc StartAngle="30" EndAngle="45" Fill="Red" />
<ed:Arc StartAngle="275" EndAngle="30" Fill="Grey" />

Related

Howto create a ordered WPF multimonth index view?

Is it possible to declare a (linked) multimonth calendar Index View Control in pure Xaml? Disregarding the public interface of the resulting control.
What i intend to get would look like this (well, kind of):
<January> <February> <..>
1234556 12345678
78910 .. 91011...
Above you see two Calendars. If one of those calendars is switched forward or backward one month, the "neighbours" also have to switch state in that direction. Additionally the number of Visible Calendars should be determined by the current width and height of the control.
First, i was thinking of a WrapPanel. But what i try to find out is how to specifiy the itemssource (list of DateTime's) and the "link" between the calendars.
Any suggestions on how to solve this in best WPF manner?
You can link the calendars by binding the DisplayDate value to its adjacent Calendar control, and using a Value Converter to adjust the month. I've include a basic prototype to get you started.
Here is the XAML:
<Window x:Class="CalendarTriggers.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Converter="clr-namespace:CalendarTriggers"
Title="MainWindow"
Height="350" Width="525">
<Window.Resources>
<Converter:CalendarConverter x:Key="conv"/>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Calendar x:Name="Month1" Grid.Column="0" DisplayDate="2011/01/11" />
<Calendar x:Name="Month2" Grid.Column="1" DisplayDate="{Binding Path=DisplayDate, ElementName=Month1, Converter={StaticResource conv}}" />
<Calendar x:Name="Month3" Grid.Column="2" DisplayDate="{Binding Path=DisplayDate, ElementName=Month2, Converter={StaticResource conv}}"/>
</Grid>
</Window>
Here is the converter:
using System;
using System.Globalization;
using System.Windows.Data;
namespace CalendarTriggers
{
public class CalendarConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
DateTime input = DateTime.Now;
try
{
input = (DateTime)value;
if (input != null)
{
input = input.AddMonths(1);
}
}
catch (Exception)
{
}
return input;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
DateTime input = DateTime.Now;
try
{
input = (DateTime)value;
if (input != null)
{
input = input.AddMonths(-1);
}
}
catch (Exception)
{
}
return input;
}
}
}

Windows Phone Silverlight - setting button IsDisabled if bound data length is 0

Here's what I've got - I'm writing an App that, among other things, reads an RSS feed to get episodes of a certain podcast, then displays each episode's title and description, with a "listen" and "watch" button. But not all the episodes have both options - the RSS will return an empty string instead of a URL for either option if it's not available. So I'm trying to use IValueConverter that I can bind IsDisabled to, which returns true if the bound data length is 0, and false otherwise. For now, I'm just testing it on the "watch" buttons, since the binding will be nearly identical for the "listen" buttons.
A snippet of MainPage.xaml.cs:
using System.Xml.Linq;
using System.Windows.Data;
namespace appname
{
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
WebClient PodcastListDownloader = new WebClient();
PodcastListDownloader.DownloadStringCompleted += new DownloadStringCompletedEventHandler(PodcastListDownloadCompleted);
PodcastListDownloader.DownloadStringAsync(new Uri("http://domain.tld/mobile_app/podcastfeed"));
}
void PodcastListDownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
return;
XElement xmlPodcastList = XElement.Parse(e.Result);
PodcastListBox.ItemsSource = from PodcastEpisode in xmlPodcastList.Descendants("item")
select new PodcastItem
{
title = PodcastEpisode.Element("date").Value + " " + PodcastEpisode.Element("title").Value,
subtitle = PodcastEpisode.Element("subtitle").Value,
description = PodcastEpisode.Element("summary").Value,
audio = PodcastEpisode.Element("audio").Value,
video = PodcastEpisode.Element("video").Value,
};
}
private void PlayPodcast(object sender, RoutedEventArgs e)
{
Button btn = (Button)sender;
Microsoft.Phone.Tasks.MediaPlayerLauncher PodcastPlay = new Microsoft.Phone.Tasks.MediaPlayerLauncher();
PodcastPlay.Media = new Uri(btn.Tag.ToString());
PodcastPlay.Show();
}
}
public class PodcastItem
{
public string title { get; set; }
public string description { get; set; }
public string audio { get; set; }
public string video { get; set; }
public string subtitle { get; set; }
}
public class StringLengthVisibilityConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null || value.ToString().Length == 0)
{
return false;
}
else
{
return true;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
A snippet of MainPage.xaml:
<phone:PhoneApplicationPage
x:Class="CCoFnow.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="800"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="False">
<Grid x:Name="LayoutRoot" Background="Transparent">
<!--Panorama control-->
<controls:Panorama Title="AppName">
<controls:Panorama.Background>
<ImageBrush ImageSource="PanoramaBackground.png"/>
</controls:Panorama.Background>
<controls:PanoramaItem Header="Podcast" Foreground="{StaticResource PhoneAccentBrush}">
<ListBox Margin="0,0,-12,0" ItemsSource="{Binding Items}" Name="PodcastListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432">
<TextBlock Text="{Binding title}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding description}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
<StackPanel Orientation="Horizontal">
<Button Content="Listen" Width="215" Tag="{Binding audio}" Click="PlayPodcast"/>
<Button Content="Watch" Width="215" Tag="{Binding video}" Click="PlayPodcast" IsEnabled="{Binding video, Converter={StringLengthVisibilityConverter}}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</controls:PanoramaItem>
</controls:Panorama>
</Grid>
</phone:PhoneApplicationPage>
But the debugger is throwing two errors:
1) The tag
'StringLengthVisibilityConverter' does
not exist in XML namespace
'http://schemas.microsoft.com/winfx/2006/xaml/presentation
2) The type
'StringLengthVisibilityConverter' was
not found. Verify that you are not
missing an assembly and that all
referenced assemblies have been built
I set the converter to {StaticResource StringLengthVisibilityConverter} instead (per http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter(v=VS.95).aspx), and now there's just one error: The resource "StringLengthVisibilityConverter" could not be resolved. With this error, I can debug (run) the code, but all the "watch" buttons remain enabled.
So I'm guessing I'm calling it in the wrong namespace, but I can't seem to figure out the correct one. Can someone please point me in the right direction?
Thanks!
Edit: In the process of putting this together, I realized that I need to do this differently - the feed now has additional values I can databind to. However, I'm quite sure I'm going to need this functionality at some point in the future, so I'm going to post anyway. If there's an easy solution for the question, please let me know so I can learn and do it sucessfully next time!
The way you reference the converter isn't quite right. You need an instance of the converter available somwhere, e.g. in the page's Resources section:
<phone:PhoneApplicationPage xmlns:conv="namespace reference for your converter goes here"
...>
<phone:PhoneApplicationPage.Resources>
<conv:StringLengthVisibilityConverter x:Key="Length" />
</phone:PhoneApplicationPage.Resources>
Then you reference that converter by using a StaticResource reference with the x:Key that you gave the converter.
<Button Content="Watch"
Width="215"
Tag="{Binding video}"
Click="PlayPodcast"
IsEnabled="{Binding video, Converter={StaticResource Length}}"/>
I'll leave the discussion of your approach versus using commands and MVVM for another day :)

Binding WPF ComboBox to List<MyClass> where MyClass doesn't have properties, just methods

I want to bind a combo box to a list of Device, List. I use,
m_ctrlCB.DataContext = m_List;
m_ctrlCB.DisplayMemberPath = "ToString()";
m_ctrlCB.SelectedValuePath = "ToString()"; // do I even need this?
I don't have any properties in Device to bind to and it's not my class. However, they do override ToString to something that is suitable for displaying in the combobox (something like: "Class Device. Number 1".
However, what I wrote doesn't work. What I see in the combobox is blank items. My selectionChanged event does work AND e.AddedItems[0] really is a Device, so I'm close. How can I get something meaningful to display in the combox box.
I suppose I'd also be happy creating ComboBoxItems and adding them to the ComboBox if necessary. But if I go this route, how do I set the Display stuff and the actual object itself so I can get it when the user selects it from the combobox?
Bonus question. If instead of using ToString, I want to use GetDeviceNumber() and combine it with my own test so the user sees,
Device #1
Device #2
how would I do this?
thanks,
Dave
You don't have to set the DisplayMemberPath and the SelectedValuePath. Since your Device object overrides ToString(), it should display the correct string on its own.
EDIT:
To answer your "bonus question", one way to do this is to use an IValueConverter that calls the method you're interested in. The sample code below demonstrates this. I have here a combobox whose items are represented by a TextBlock (which shows the value for the ToString() method), as well as a Button (which shows the value for the GetDeviceNumber() method).
XAML:
<Window x:Class="StackOverflow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:StackOverflow"
Title="MainWindow" Height="350" Width="525"
x:Name="window">
<ComboBox x:Name="cb">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}"/>
<Button>
<Button.Content>
<Binding>
<Binding.Converter>
<local:DeviceValueConverter/>
</Binding.Converter>
</Binding>
</Button.Content>
</Button>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Window>
Code-Behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.cb.ItemsSource = new List<Device>()
{
new Device("Device1"),
new Device("Device2"),
new Device("Device3"),
};
}
}
public class Device
{
private string text;
public Device(string text)
{
this.text = text;
}
public string GetDeviceNumber() { return this.GetHashCode().ToString(); }
public override string ToString() { return this.text; }
}
public class DeviceValueConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is Device)
{
return (value as Device).GetDeviceNumber();
}
return string.Empty;
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new System.NotImplementedException();
}
#endregion
}
One way you could do it would be to create a wrapper class and provide the appropriate properties on it. For example:
class DeviceWrapper
{
private Device device;
public DeviceWrapper(Device device)
{
this.device = device;
}
public int DeviceNumber
{
return this.device.GetDeviceNumber();
}
// etc...
}
You should try to use ObjectDataProvider.
It will be something like this
...
<UserControl.Resources>
<ObjectDataProvider MethodName="GetValues"
ObjectType="{x:Type sys:Enum}"
x:Key="AlignmentValues">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="HorizontalAlignment" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</UserControl.Resources>
<Border Margin="10" BorderBrush="Aqua"
BorderThickness="3" Padding="8">
<StackPanel Width="300">
<TextBlock>bla-bla</TextBlock>
<ListBox Name="myComboBox" SelectedIndex="0" Margin="8"
ItemsSource="{Binding Source={StaticResource AlignmentValues}}"/>
<Button Content="Click Me!"
HorizontalAlignment="{Binding ElementName=myComboBox,
Path=SelectedItem}"/>
</StackPanel>
</Border>
...

Mvvm Silverlight, using binding to Programmatically style rows in a SilverLight DataGrid

Is it possible to bind a rows in a Silverlight DataGrid to some sort of style property in a ViewModel so that styles can be applied programatically / dynamically?
I've been using the Mvvm-Light toolkit quite successfully to create an mvvm silverlight app, this is the first major stumbling block I have hit.
Thanks in advance for any help.
There is no data template selector or type specific data templates in Silverlight. One way to work around this is to have a property in your ViewModel that triggers the visibility of something in the XAML. For instance, have an element in your your DataGrid's item template where the Visibility is bound to a property like IsSelected in your ViewModel, and use a BooleanToVisibility value converter.
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="130" />
<ColumnDefinition Width="70" />
<ColumnDefinition Width="70" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<Grid Grid.ColumnSpan="4"
Visibility="{Binding Path=IsSelected, Converter={StaticResource BoolToVisibilityConverter}}">
<Border Style="{StaticResource SelectedDataGridRowStyle}" />
</Grid>
<!-- other stuff here -->
</Grid>
</DataTemplate>
In case you haven't defined your own Boolean to Visbility value converter yet ...
public class BoolToVisibilityConverter : System.Windows.Data.IValueConverter
{
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var visible = true;
if (value != null && value is bool)
visible = (bool)value;
var reverse = false;
if (parameter != null)
reverse = System.Boolean.Parse((string)parameter);
visible = reverse ? !visible : visible;
return visible ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed;
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var visibility = System.Windows.Visibility.Visible;
if (value != null && value is System.Windows.Visibility)
visibility = (System.Windows.Visibility)value;
var reverse = false;
if (parameter != null && parameter is bool)
reverse = (bool)parameter;
var visible = visibility == System.Windows.Visibility.Visible;
visible = reverse ? !visible : visible;
return visible;
}
}

Storing a radio button selection in the settings

I've been looking at this article but am having issues saving the enumerated value in the settings.
I have created the following enum
public enum FType
{
None,
Delimited,
FixedWidth,
XML
};
I have the radio button selection working nicely but I now want to store the selected option in the settings but there doesn't appear to be the ability to store an enumerated variable.
I assumed I could convert the enum to a string and then convert back but being a bit of a noob when it comes to WPF I'm not realy sure where to start.
Here is the code I've generated so far:
App.Xaml
<Application x:Class="Widget.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:properties="clr-namespace:Widget.Properties"
StartupUri="Window1.xaml"
Exit="Application_Exit">
<Application.Resources>
<properties:Settings x:Key="Settings" />
</Application.Resources>
</Application>
App.xaml.cs
public partial class App : Application
{
private void Application_Exit(object sender, ExitEventArgs e)
{
Widget.Properties.Settings.Default.Save();
}
}
Windows.xaml
<Window x:Class="Widget.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Widget"
Title="Window1" Height="85" Width="300">
<Window.Resources>
<local:EnumBooleanConverter x:Key="enumBooleanConverter"/>
</Window.Resources>
<Grid>
<StackPanel>
<RadioButton GroupName="FileType" Content="Delimited" IsChecked="{Binding Path=Default.FileType, Mode=TwoWay, Converter={StaticResource enumBooleanConverter}, ConverterParameter=Delimited}" />
<RadioButton GroupName="FileType" Content="Fixed Width" IsChecked="{Binding Path=Default.FileType, Mode=TwoWay, Converter={StaticResource enumBooleanConverter}, ConverterParameter=FixedWidth}"/>
<RadioButton GroupName="FileType" Content="XML" IsChecked="{Binding Path=Default.FileType, Mode=TwoWay, Converter={StaticResource enumBooleanConverter}, ConverterParameter=XML}"/>
</StackPanel>
</Grid>
</Window>
Converter.cs
public class EnumBooleanConverter : IValueConverter
{
public EnumBooleanConverter()
{
}
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string parameterString = parameter as string;
if (parameterString == null)
return DependencyProperty.UnsetValue;
if (Enum.IsDefined(value.GetType(), value) == false)
return DependencyProperty.UnsetValue;
object parameterValue = Enum.Parse(value.GetType(), parameterString);
return parameterValue.Equals(value);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string parameterString = parameter as string;
if (parameterString == null)
return DependencyProperty.UnsetValue;
return Enum.Parse(targetType, parameterString);
}
#endregion
}
Your code looks just fine, except 2 problems that I think may be preventing you from storing settings:
I think you should specify a DataContext for your RadioButtons. Just modify your Window1 like this:
<StackPanel DataContext="{StaticResource Settings}">
<RadioButton GroupName=... />
<RadioButton GroupName=... />
<RadioButton GroupName=... />
</StackPanel>
(Note: If StaticResource doesn't work try using DynamicResource)
Secondly, from your post it seems that you are storing values as string in settings. Just change this and instead set datatype of FileType to Ftype. (If you don't know how 2 do this, tell me)
After doing these 2 changes you'll surely get this working! I hope ;)

Resources