vertically scrolling gridview XAML windows store app - c#

how to edit GRIDVIEW in windows store app xaml so that we can make it scroll vertically instead of horizontal.
am using XAML should we manually make a new user element using scroll-view or is there any simple way to achieve this with windows store app .
<GridView HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="{Binding imagelist}">
<GridView.Resources>
<DataTemplate x:Key="DataTemplate1">
<Grid Width="250" Height="250" Tapped="Grid_Tapped">
<Image Source="{Binding imsourceurl}"/>
</Grid>
</DataTemplate>
</GridView.Resources>
<GridView.ItemTemplate>
<StaticResource ResourceKey="DataTemplate1"/>
</GridView.ItemTemplate>
</GridView>

solved created custom grid-view template
public class AdaptableGridView : GridView
{
// default itemWidth
private const double itemWidth = 100.00;
public double ItemWidth
{
get { return (double)GetValue(ItemWidthProperty); }
set { SetValue(ItemWidthProperty, value); }
}
public static readonly DependencyProperty ItemWidthProperty =
DependencyProperty.Register("ItemWidth", typeof(double), typeof(AdaptableGridView), new PropertyMetadata(itemWidth));
// default max number of rows or columns
private const int maxRowsOrColumns = 3;
public int MaxRowsOrColumns
{
get { return (int)GetValue(MaxRowColProperty); }
set { SetValue(MaxRowColProperty, value); }
}
public static readonly DependencyProperty MaxRowColProperty =
DependencyProperty.Register("MaxRowsOrColumns", typeof(int), typeof(AdaptableGridView), new PropertyMetadata(maxRowsOrColumns));
public AdaptableGridView()
{
this.SizeChanged += MyGridViewSizeChanged;
}
private void MyGridViewSizeChanged(object sender, SizeChangedEventArgs e)
{
// Calculate the proper max rows or columns based on new size
this.MaxRowsOrColumns = this.ItemWidth > 0 ? Convert.ToInt32(Math.Floor(e.NewSize.Width / this.ItemWidth)) : maxRowsOrColumns;
}
}
xaml:
<local:AdaptableGridView ItemWidth="250" x:Name="tumbview" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" ItemsSource="{Binding imagelist}" SelectionChanged="GridView_SelectionChanged" Margin="50,0,0,0" >
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid Orientation="Horizontal"
ItemWidth="{Binding ElementName=tumbview, Path=ItemWidth}"
MaximumRowsOrColumns="{Binding ElementName=tumbview, Path=MaxRowsOrColumns}"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
nice tutorial at:custom grid view tutorial

I found the easiest way was just to use a ListView and set the items to be a wrappedgrid.
This works for me
<ListView
Width="1300"
Height="1000"
Margin="20,0,20,0">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid MaximumRowsOrColumns="3" Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
Check out http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.controls.wrapgrid.aspx

Related

How do I flip this "grid" of displayed objects to be in 3x2 instead of 2x3

I am trying to show the user a bunch of data based on a grid (not the ui element grid). The data changes and the displayed instances are based on the X/Y position of that data. I used an example I found here (but can't find it right now) and I basically got everything working. Except that the displayed grid is on it's side. I have created a test project under which I'm trying to make the thing work correctly before taking that to my main project.
Here is what it looks like
Here is what I want it to look like (Tanks Paint)
Codebehind: (Quick and dirty but works for testing purposes)
private DataContainer[][] dataArray;
public MainWindow()
{
dataArray = new DataContainer[3][];
dataArray[0] = new DataContainer[2];
dataArray[1] = new DataContainer[2];
dataArray[2] = new DataContainer[2];
dataArray[0][0] = new DataContainer(1,"At: 0,0");
dataArray[1][0] = new DataContainer(2, "At: 1,0");
dataArray[2][0] = new DataContainer(3, "At: 2,0");
dataArray[0][1] = new DataContainer(4, "At: 0,1");
dataArray[1][1] = new DataContainer(5, "At: 1,1");
dataArray[2][1] = new DataContainer(6, "At: 2,1");
InitializeComponent();
lst.ItemsSource = dataArray;
}
XAML:
<Window.Resources>
<DataTemplate x:Key="DataTemplate_Level2">
<Border Name="border" BorderBrush="LightGreen" BorderThickness="5"
Padding="2" Margin="2" Width="80">
<Grid Margin="2">
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Border Name="border2" BorderBrush="Red" BorderThickness="2"
Grid.Row ="0" Padding="1" Margin="1">
<TextBlock Text="{Binding Path=Text1, UpdateSourceTrigger=PropertyChanged}"/>
</Border>
<Border Name="border3" BorderBrush="Blue" BorderThickness="2"
Grid.Row ="1" Padding="1" Margin="1">
<TextBlock Text="{Binding Path=Number1, UpdateSourceTrigger=PropertyChanged}"/>
</Border>
</Grid>
</Border>
</DataTemplate>
<DataTemplate x:Key="DataTemplate_Level1">
<ItemsControl ItemsSource="{Binding}" ItemTemplate="{DynamicResource DataTemplate_Level2}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</Window.Resources>
<Grid>
<ItemsControl x:Name="lst" ItemTemplate="{DynamicResource DataTemplate_Level1}"/>
</Grid>
What I've tried:
I tried changing stackpanel orientation to Vertical. That got me half way there. The Result is left column on top of right column. The problem is changing the 3 elements within that column to be Horizontal, which should give the result I'm looking for.
I also triend fondling the DataTemplate_Level2 but that just left me with error messages.
To be honest, I'm new to WPF (in case you haven't noticed) This databinding and templating is the most complicated UI part of my project and I've been thoroughly confused by trying to learn all the stuff at once. I would appreciate it if someone would point me towards an answer here. It's almost Christmas and I would much rather not spend the holidays thinking about this problem.
One solution I can think of is swapping the X and Y coordinates in the array to be dataArray[Y][X] instead of dataArray[X][Y] but that would make things difficult for me in the future and it would be best to get the problems solved now.
In case you wonder what the datacontainer object looks like, but this shouldn't be important to the solution of this issue. it's just something I whipped together to demonstrate that I have gotten the binding and updating to work. It just displays the coordinates it should be at and at random interval changes the value of the number:
public class DataContainer : INotifyPropertyChanged
{
private int number1 = 0;
private string text1 = "none";
private System.Timers.Timer aTimer;
public event PropertyChangedEventHandler PropertyChanged;
public DataContainer(int num,string str)
{
number1 = num;
text1 = str;
aTimer = new System.Timers.Timer(num*1000);
aTimer.Elapsed += OnTimedEvent;
aTimer.AutoReset = true;
aTimer.Enabled = true;
}
private void OnTimedEvent(object sender, ElapsedEventArgs e)
{
Random r = new Random();
number1 = r.Next(0, 100);
number1 += 1;
this.NotifyPropertyChanged("Number1");
}
public int Number1
{
get { return this.number1; }
set
{
if (this.number1 != value)
{
this.number1 = value;
this.NotifyPropertyChanged("Number1");
}
}
}
public string Text1
{
get { return this.text1; }
set
{
if (this.text1 != value)
{
this.text1 = value;
this.NotifyPropertyChanged("Text1");
}
}
}
public void NotifyPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
public MainWindow()
{
InitializeComponent();
lst.ItemsSource = new List<DataContainer>
{
new DataContainer(1, "At: 0,0"),
new DataContainer(2, "At: 1,0"),
new DataContainer(3, "At: 2,0"),
new DataContainer(4, "At: 0,1"),
new DataContainer(5, "At: 1,1"),
new DataContainer(6, "At: 2,1")
}
}
<ItemsControl x:Name="lst" ItemTemplate="{DynamicResource DataTemplate_Level2}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformsGrid Columns="3" Rows="2"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
I had some sleep and tested out some things and figured out where exactly things are going wrong by adding more borders. Here's the solution that I found myself:
<ItemsControl x:Name="lst" ItemTemplate="{DynamicResource DataTemplate_Level1}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
and the data template:
<DataTemplate x:Key="DataTemplate_Level1">
<ItemsControl ItemsSource="{Binding}" ItemTemplate="{DynamicResource DataTemplate_Level2}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>

Binding data in listview itemtemplate using style

I cannot bind my sample data to textblocks in stackpanel, which I defined in resources. I think that I use style in wrong way, because I receive toString() method instead of class binded fields.
That's my resources with defined style:
<UserControl.Resources>
<ItemsPanelTemplate x:Key="VirtualizingStackPanelTemplate">
<VirtualizingStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
<ListView x:Key="ListBoxTemplate" HorizontalAlignment="Left" ScrollViewer.HorizontalScrollBarVisibility="Visible">
<ListView.ItemTemplate>
<DataTemplate>
<!--<ListBoxItem Background="DarkOrchid" Margin="1,1, 5,5" Height="400" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch">-->
<StackPanel>
<TextBlock FontSize="30" Text="{Binding Title}"/>
<TextBlock FontSize="20" Text="{Binding Desc}"/>
</StackPanel>
<!--</ListBoxItem>-->
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</UserControl.Resources>
Here is my method in which i add listview programatically:
long rowCount = ContentGridFullView.RowDefinitions.LongCount();
if (rowCount > 8) return;
var c1 = new RowDefinition { Height = new GridLength(1, GridUnitType.Star) };
ContentGridFullView.RowDefinitions.Add(c1);
rowCount = ContentGridFullView.RowDefinitions.LongCount();
TextBlock tb = new TextBlock {Text = "TEXTBLOCK ITEM = " + (rowCount - 1), FontSize = 40};
Viewbox vb = new Viewbox { Child = tb };
if (rowCount > 8) return;
Grid.SetRow(vb, Convert.ToInt32(rowCount-1));
Grid.SetColumn(vb, 1);
ListView lb = new ListView();
lb.Style = Resources["ListBoxTemplate"] as Style;
lb.ItemsPanel = (ItemsPanelTemplate) Resources["VirtualizingStackPanelTemplate"];
var products = new ObservableCollection<Product>() { new Product("ASDASDSADAS", "VCBVCBVCBVCBC"), new Product("ASDASDSADAS", "VCBVCBVCBVCBC"), new Product("ASDASDSADAS", "VCBVCBVCBVCBC"), new Product("ASDASDSADAS", "VCBVCBVCBVCBC") };
lb.ItemsSource = products;
ContentGridFullView.Children.Add(lb);
ContentGridFullView.Children.Add(vb);
Grid.SetRow(lb, Convert.ToInt32(rowCount - 1));
Grid.SetColumn(lb, 2);
And my short class that I want to bind:
public class Product
{
public string Title { get; set; }
public string Desc { get; set; }
public Product(string title, string desc)
{
Title = title;
Desc = desc;
}
public override string ToString()
{
return "I see that message instead of Title and Desc";
}
}
Can someone tell me what's wrong with this code? Thank you.
Create your Observable collection as a property (getter/setter):
ObservableCollection<Product> _products;
public ObservableCollection<Product> products
{
get{return _products;}
set
{
_products=value;
PropertyChanged("products");
}
}
The property changed event will be need to indicate that the collection has changed,its needed when your using ObservableCollection. You'll need to read more about it.You can add items to the products collection by using :
products.Add(Product_object)
And your xaml code will have the itemsSource as follows:
<ListView x:Key="ListBoxTemplate" HorizontalAlignment="Left" ScrollViewer.HorizontalScrollBarVisibility="Visible" ItemsSource="{Binding products}">
<ListView.ItemTemplate>
<DataTemplate>
<!--<ListBoxItem Background="DarkOrchid" Margin="1,1, 5,5" Height="400" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch">-->
<StackPanel>
<TextBlock FontSize="30" Text="{Binding Title}"/>
<TextBlock FontSize="20" Text="{Binding Desc}"/>
</StackPanel>
<!--</ListBoxItem>-->
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The following statement is important in your xaml code so that your xaml code will know where to look for the data.
DataContext="{Binding RelativeSource={RelativeSource Self}, Path=x}
First try and create a static list and check if data is getting initialized properly and then you can try creating listviews dynamically. But the code above will be the same thing you will have to do create dynamic listviews.

How to Display Gridview items with variable width in Windows 8?

My GridView items having the size of it's first item size. How do i can change this behaviour ?
How to display GridView items with variable Width as per the content ?
I want to show the first one but i am getting second one. Any suggestion to do that?
Check Windows 8 GridView and Variable-Sized Items and Different Sized Tile Items in WinRT GridView and also check Variable Sized Grid Template Hope this help
You can create such view of GridView by setting ItemsPanel to WrapPanel, you can get WrapPanel on Jerry Nixon's blog. Here's the code.
XAML
<GridView x:Name="gv">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<local:WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.ItemTemplate>
<DataTemplate>
<Grid Height="140" Width="{Binding MyWidth}">
<Grid.Background>
<SolidColorBrush Color="{Binding MyColor}" />
</Grid.Background>
<TextBlock FontSize="20" VerticalAlignment="Bottom" Margin="10,0,0,10">
<Run Text="{Binding MyWidth}" />
</TextBlock>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
C#
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var list = new List<ViewModel>()
{
new ViewModel(110, Colors.LawnGreen),
new ViewModel(50, Colors.DarkBlue),
new ViewModel(130, Colors.Firebrick),
new ViewModel(60, Colors.RosyBrown),
new ViewModel(100, Colors.IndianRed),
new ViewModel(210, Colors.BurlyWood),
new ViewModel(150, Colors.Turquoise)
};
gv.ItemsSource = list;
}
public class ViewModel
{
public double MyWidth { get; set; }
public Color MyColor { get; set; }
public ViewModel(double _MyWidth, Color _MyColor)
{
MyWidth = _MyWidth;
MyColor = _MyColor;
}
}
Here is my solution.
//variable sized grid view
public class VariableSizedGridView : GridView
{
protected override void PrepareContainerForItemOverride(Windows.UI.Xaml.DependencyObject element, object item)
{
try
{
dynamic gridItem = item;
var typeItem = item as CommonType;
if (typeItem != null)
{
var heightPecentage = (300.0 / typeItem.WbmImage.PixelHeight);
var itemWidth = typeItem.WbmImage.PixelWidth * heightPecentage;
var columnSpan = Convert.ToInt32(itemWidth / 10.0);
if (gridItem != null)
{
element.SetValue(VariableSizedWrapGrid.ItemWidthProperty, itemWidth);
element.SetValue(VariableSizedWrapGrid.ColumnSpanProperty, columnSpan);
element.SetValue(VariableSizedWrapGrid.RowSpanProperty, 1);
}
}
}
catch
{
element.SetValue(VariableSizedWrapGrid.ItemWidthProperty, 100);
element.SetValue(VariableSizedWrapGrid.ColumnSpanProperty, 1);
element.SetValue(VariableSizedWrapGrid.RowSpanProperty, 1);
}
finally
{
base.PrepareContainerForItemOverride(element, item);
}
}
//Collection View source
<CollectionViewSource x:Name="collectionViewSource"
Source="{Binding ImageList,Mode=TwoWay}"
IsSourceGrouped="False"
ItemsPath="Items" />
//variable sized Grid view xaml
<controls:VariableSizedGridView x:Name="ImageGridView"
AutomationProperties.AutomationId="ImageGridView"
ItemsSource="{Binding Source={StaticResource collectionViewSource}}"
IsItemClickEnabled="True"
TabIndex="1" >
<controls:VariableSizedGridView.ItemTemplate>
<DataTemplate>
<Grid Height="300" >
<Image Stretch="Uniform" Source="{Binding WbmImage}" />
</Grid>
</DataTemplate>
</controls:VariableSizedGridView.ItemTemplate>
<controls:VariableSizedGridView.ItemsPanel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid ItemWidth="10" ItemHeight="300" Orientation="Vertical"/>
</ItemsPanelTemplate>
</controls:VariableSizedGridView.ItemsPanel>
</controls:VariableSizedGridView>

Stackpanel/Itemscontrol Databinding

I have this XAML:
<ItemsControl x:Name="recentSearches"
Margin="0,65,0,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding q}"
TextWrapping="Wrap"
Foreground="AliceBlue"
Padding="2,6,2,2"
Margin="12,-6,12,0"
FontSize="20" />
</DataTemplate>
</ItemsControl.ItemTemplate>
and this code behind:
private void showLatestSearches()
{
if (fmn.checkLatestSearchesExtistence())
{
List<RecentSearchItem> recent = new List<RecentSearchItem>();
List<String> l = fmn.readLatestSearches();
for (int i = 0; i <= l.Count-1; i += 1)
{
RecentSearchItem r = new RecentSearchItem();
r.q = l[i];
r.generalbg = grau;
recent.Add(r);
}
recentSearches.DataContext = recent;
}
}
the object called fmn reads a .txt from the isolated storage.
But why doesn't anything show up with this StackPanel?
ItemsControl.ItemsSource has to be bound to a collection, for notifications the best would be ObservableCollection<T>.
You are setting the DataContext at the last possible minute, a better way would be to set
DataContext to a ViewModel, could be place where you create your View.
public class Form :UserControl
{
DataContext = new YourViewModel() ;
}
In XAML:
ItemsSource="{Binding SearchesCollection}"
SearchesCollection would be a property in YourViewModel of type ObservableCollection<string>. Whenever you add a new item to SearchesCollection the View updates.
This Databinding Tutorial should help.
Thanks to Lews Therin I managed to finally bind my data to the stackpanel:
<ItemsControl x:Name="recentSearches"
ItemsSource="{Binding recent}"
Background="{Binding generalbg}"
Margin="0,65,0,0" Tap="recentSearches_Tap">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding q}"
Foreground="{Binding foreground}"
TextWrapping="Wrap"
Padding="2,6,2,2"
Margin="12,-6,12,0"
FontSize="20" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
and the code behind:
private void showLatestSearches()
{
if (fmn.checkLatestSearchesExtistence())
{
List<RecentSearchItem> recent = new List<RecentSearchItem>();
List<String> l = fmn.readLatestSearches();
for (int i = 0; i <= l.Count-1; i += 1)
{
RecentSearchItem r = new RecentSearchItem();
r.q = l[i];
r.generalbg = grau;
r.foreground = blau;
recent.Add(r);
}
recentSearches.ItemsSource = recent;
}
}
this works, but unfortunately there seems to be no way to determine, which TextBox is tapped, when one is tapped.

Bind a listbox inside a listbox to an observable collection? Best approach?

In xaml, I have a listbox with a grid in it with 1 row and 2 columns. In the first column I have a name, and in the second column I have another listbox...I have the first listbox bound to an observable collection of Enclosure items. In the Enclosure class, I have another observablecollection of Servers (another class). I am trying to bind this to a listbox as well. The EnclosureID is working and updating properly as I add items to the observable collection. However, I am not so sure how to get the Slist to bind to the listbox I have within my other listbox. Anyone have any ideas? Is there another approach I can use?
public class Enclosure
{
private string enclosureID; //bound to the first listbox
//I want to bind this below to the second listbox
//There is another class called Server with various properties
public ObservableCollection<Server> Slist = new ObservableCollection<Server>();
public string EnclosureID
{
get { return enclosureID; }
set { enclosureID = value; }
}
}
In xaml:
<ListBox x:Name="lb1" ItemsSource="{Binding}" DataContext="{Binding}" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="txtEnclosure" Text="{Binding Path=EnclosureID}" Background="Aqua" Grid.Column="0" Grid.Row="0" />
<ListBox x:Name="lbserver" ItemsSource="{Binding Slist}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" Grid.Column="1" Grid.Row="0">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock x:Name="txtServer" Text="{Binding Path=HostnameID}" Background="Beige"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
To populate lists I use this method:
//Query the database for enclosures and populate the Enclosure observable collection in the Settings class
public void GetEnclosures()
{
bool exception = false;
Enclosure enclosure = new Enclosure();
Server server = new Server();
server.HostnameID = "HEY";
OleDbCommand GetEnclosuresCommand = new OleDbCommand(Settings.GetEnclosuresQuery, Settings.conn);
Settings.conn.Open();
try
{
Settings.myReader = GetEnclosuresCommand.ExecuteReader();//begin reading
}
catch
{
MessageBox.Show("The Enclosure table is currently being used by another application. Please close the table and run this application again.");
Settings.conn.Close();
exception = true;
}
if (!exception)
{
// while there are enteries to retrieve
while (Settings.myReader.Read())
{
enclosure.EnclosureID = Settings.myReader.GetString(0);
enclosure.Slist.Add(server);
Settings.Elist.Add(enclosure);
enclosure = new Enclosure();
server = new Server();
server.HostnameID = "HI";
}
// Close when done reading.
Settings.myReader.Close();
// Close the connection.
Settings.conn.Close();
}
else
{
this.NavigationService.Navigate(new Uri("MainPage.xaml", UriKind.Relative));
}
}
Could be wrong, but isn't as as simple as...
<ListBox
x:Name="lbserver"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
Grid.Column="1"
Grid.Row="0"
ItemsSource="{Binding Slist}">
Also change this
public ObservableCollection<Server> Slist = new ObservableCollection<Server>();
to say
public ObservableCollection<Server> Slist { get; set; }
//...
Slist = new ObservableCollection<Server>();

Categories