Archive for the 'Coding' Category

LINQ - OrderBy Method and Multiple Fields

Just a friendly helpful tip - if you are using LINQ and have, for example, a list of objects, you can use the OrderBy() method to order it. But in order to order it by additional column criteria, use the following:

listView.DataSource = myList.OrderBy(i => i.Field1).ThenBy(i => i.Field2);

Additionally, the OrderByDescending() and ThenByDescending() methods also exist to assit you.

ASP.NET Web Services & XElement Return Types

I’ve been a huge fan of LINQ to XML. So I have been trying to have a ASP.NET ASMX Web Service with several WebMethods return XElements. You cannot return the XDocument as it is not serializable. However, XElements are. But, in my experimentation, after having a few XElements returned, I receive an IllegalOperationException: Cannot use wildcards at the top level of a schema.

Here is an example of what I was trying to do:

using...
namespace WebServiceTest
{
    public class WebServiceTest : WebService
    {
        [WebMethod]
        public XElement OhHai()
        {
            return new XElement("OhHai");
        }

        [WebMethod]
        public XElement GetCheezburger()
        {
            return new XElement("ICanHasCheezburger");
        }

        [WebMethod]
        public XElement Errored()
        {
            return new XElement("KTHXBYE");
        }
    }
}

I have attempted this on three different computers with Visual Studio 2008. All behave correctly with one or two, but usually when adding the third, I get the exception. If I change the third to return something else, it works fine. Very strange. Obviously it’s some kind of bug on the .NET side of the world. I guess it still is best to return an XmlNode or even a string (but can sometimes be unpredictable)…

One last note for you beginners to LINQ to XML. When using XElements or XDocuments, you have really a lot at your disposal to convert this to something else. You can use the CreateReader or CreateWriter methods, ToString works, etc. My preferred method, however, is calling the WriteTo method. This allows the XML as it should be represented to be output flawlessly every time.

WPF ListView Not Refreshing

I’ve spent the last few days tracking down how to get a ListView to refresh its associated generic list collection which is populated via LINQ to SQL. My UI is more complex than the below example, but you’ll get the idea. I essentially wanted a ListView that gets populated from a LINQ to SQL object. As the binding is occurring, I want it to check to see if the transaction has been voided. If it has, I want it to disable the Void button. I do this check view an IValueConverter. This was working, but after clicking on an unvoided transaction, the button’s IsEnabled property wasn’t changing. And after reading many posts, ranging from using ObservableCollections to changing the ListView.DataContext to changing the ListView.ItemsSource of the list, I still wasn’t able to find a simple solution to my seemingly simple problem.

After much trial and error - I thought I’d share with the world what I did to remedy it:

The XAML

MyWindow.xaml

...
<Window.CommandBindings>
    <CommandBinding Command="{x:Static MyWindow.VoidTransactionCommand}"
                    Executed="VoidTransaction" />
</Window.CommandBindings>
...
<ListView Margin="0,0,0,0" Name="myList" FontSize="10" FontFamily="Tahoma"
          Height="189"
          Width="585">
    <ListView.View>
        <GridView>
            <GridViewColumn Header="ID#"
                            DisplayMemberBinding="{Binding Path=ID}" />
            <GridViewColumn Header="Voided?">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <Button Content="Void"
                                IsEnabled="{Binding Path=IsVoided, Converter={StaticResource oppositeBooleanConverter}}"
                                Command="{x:Static MyWindow.VoidTransactionCommand}"
                                CommandParameter="{Binding Path=ID}">
                        </Button>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
        </GridView>
    </ListView.View>
</ListView>
...

Teh Code :D

MyWindow.CodeBehind

...
private SomeDataContext db = new SomeDataContext(ConfigurationManager.ConnectionStrings["ConnString"].ConnectionString);
private List<SomeObject> privateList;
...
public static RoutedCommand VoidTransactionCommand = new RoutedCommand();
private void VoidTransaction(object sender, ExecutedRoutedEventArgs args)
{
	bool wasSuccess = insert some method that voids the transaction;
	if (!wasSuccess)
	{
		MessageBox.Show("This transaction could not be voided.");
	} else
	{
		db.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, privateList);
		ICollectionView view = CollectionViewSource.GetDefaultView(myList.ItemsSource);
		view.Refresh();
	}
}

OppositeBooleanConverter.cs

public class OppositeBooleanConverter : IValueConverter {
	public object Convert(object value, Type targetType, object
		parameter, System.Globalization.CultureInfo culture)
	{
		try
		{
			return !(bool)value;
		} catch {}
		return value;
	}

	public object ConvertBack(object value, Type targetType, object parameter,
		System.Globalization.CultureInfo culture)
	{
		return null;
	}
}

The Solution

Above in blue, you’ll notice that I call the DataContext.Refresh() method. And since it is overriden by the web method that I call in my implementation, I don’t want the UI to update the database, so I have the RefreshMode.OverwriteCurrentValues of the window-level field privateList. This will reset the data, but then you need to get a reference to the ICollectionView of the ListView.ItemsSource and call the Refresh() method of that, thereby loading your refreshed data into the view.