删除行和同一行中的所有控件
Removing Row & All Controls in Same Row
下面我将附上我的 window 的整个 class(这是 wpf)。我将评论我认为是 issues/concerns/problems 的内容,然后我将在下面按列表顺序解释我的评论。最有帮助的答案将是那些使用代码作为参考来回答列出的问题的人。我会提供mainwindowcs和RowContainerclass(简单管理class)。
这是 gui 的图片...
public partial class MainWindow : Window
{
public static DebugWindow debugWindow;
public static MainWindow mainWindow;
public static Dispatcher mainWindowDispacter;
private Object locker = new Object();
public ConnectionHandle ConnectionHandler;
public RowContainer[] RowContents;
public MainWindow()
{
InitializeComponent();
mainWindow = this;
mainWindowDispacter = this.Dispatcher;
}
public RowContainer RowExists(Client c)
{
if (RowContents == null)
return null;
foreach (RowContainer r in RowContents)
{
if (r.GetClient().getUID().Equals(c.getUID()))
return r;
}
return null;
}
// ----------------1 --------------------
public void RemoveFromRowList(RowContainer r)
{
List<RowContainer> l = new List<RowContainer>();
List<int> usedList = new List<int>();
int deleteRowNumber = r.rowNumber;
foreach (RowContainer rr in RowContents)
{
if (!r.Equals(rr))
{
if (rr.rowNumber > deleteRowNumber)
rr.rowNumber--;
l.Add(rr);
}
}
RowContents = l.ToArray();
}
//----------------------- 2 -------------------
public void AddToRowList(RowContainer r)
{
if (RowContents == null)
{
r.rowNumber = 1;
RowContents = new RowContainer[] { r };
return;
}
List<RowContainer> l = new List<RowContainer>();
List<int> usedList = new List<int>();
foreach (RowContainer rr in RowContents)
{
l.Add(rr);
usedList.Add(rr.rowNumber);
}
Console.WriteLine(usedList.ToString());
int? firstAvailable = Enumerable.Range(1, int.MaxValue)
.Except(usedList)
.FirstOrDefault();
r.rowNumber = (int)firstAvailable;
l.Add(r);
RowContents = l.ToArray();
}
private void onDebugLogClick(object sender, RoutedEventArgs e)
{
if (debugWindow == null)
{
debugWindow = new DebugWindow();
debugWindow.Show();
}
else
{
if (debugWindow.IsVisible)
{
debugWindow.Hide();
}
else
debugWindow.Visibility = Visibility.Visible;
}
}
public BitmapImage ToImage(byte[] array)
{
using (var ms = new System.IO.MemoryStream(array))
{
var image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = ms;
image.EndInit();
return image;
}
}
// type 0 - image, 1 - status, 2 - OS, 3 - Idle, 4 - bitaccount
public void UpdateRowContainer(RowContainer r, int type)
{
switch (type)
{
case 0:
BitmapImage image = ToImage(r.Image);
System.Windows.Controls.Image uiImage = (System.Windows.Controls.Image)MyGrid.Children.Cast<UIElement>().First(e => Grid.GetRow(e) == r.rowNumber & Grid.GetColumn(e) == 0);
if (uiImage == null)
{
}
else
{
uiImage.Source = image;
}
break;
case 2:
Label OsLabel = (System.Windows.Controls.Label)MyGrid.Children.Cast<UIElement>().First(e => Grid.GetRow(e) == r.rowNumber & Grid.GetColumn(e) == 5);
OsLabel.Content = r.Os;
break;
case 3:
Label idleLabel = (System.Windows.Controls.Label)MyGrid.Children.Cast<UIElement>().First(e => Grid.GetRow(e) == r.rowNumber & Grid.GetColumn(e) == 3);
idleLabel.Content = r.idle;
break;
}
}
// --------------------------- 3----------------------
public void CreateClientRowContainer(Client c, byte[] imageBytes)
{
RowContainer newContainer = new RowContainer(c);
BitmapImage image = ToImage(imageBytes);
newContainer.Image = imageBytes;
Label cLabel = new Label();
Label osLabel = new Label();
Label stateLabel = new Label();
Label bitAccountLabel = new Label();
Label idleTimeLabel = new Label();
osLabel.Content = "N/A";
stateLabel.Content = "N/A";
bitAccountLabel.Content = "N/A";
idleTimeLabel.Content = "N/A";
cLabel.Content = c.getClientIp();
cLabel.SetValue(Grid.ColumnProperty, 1);
stateLabel.SetValue(Grid.ColumnProperty, 2);
idleTimeLabel.SetValue(Grid.ColumnProperty, 3);
bitAccountLabel.SetValue(Grid.ColumnProperty, 4);
osLabel.SetValue(Grid.ColumnProperty, 5);
int rowCount = this.MyGrid.RowDefinitions.Count;
this.MyGrid.RowDefinitions.Add(new RowDefinition());
Style style = this.FindResource("LabelTemplate") as Style;
Style style2 = this.FindResource("OSTemplate") as Style;
cLabel.Style = style;
stateLabel.Style = style;
bitAccountLabel.Style = style;
idleTimeLabel.Style = style;
osLabel.Style = style2;
cLabel.SetValue(Grid.RowProperty, rowCount);
bitAccountLabel.SetValue(Grid.RowProperty, rowCount);
stateLabel.SetValue(Grid.RowProperty, rowCount);
idleTimeLabel.SetValue(Grid.RowProperty, rowCount);
osLabel.SetValue(Grid.RowProperty, rowCount);
System.Windows.Controls.Image imgIcon = new System.Windows.Controls.Image();
imgIcon.Height = 150;
imgIcon.HorizontalAlignment = HorizontalAlignment.Center;
imgIcon.VerticalAlignment = VerticalAlignment.Top;
imgIcon.Source = image;
MyGrid.Children.Add(cLabel);
MyGrid.Children.Add(idleTimeLabel);
MyGrid.Children.Add(stateLabel);
MyGrid.Children.Add(bitAccountLabel);
MyGrid.Children.Add(osLabel);
ConnectionHandle.SendRequestInformation(c, 3);
imgIcon.SetValue(Grid.ColumnProperty, 0);
imgIcon.SetValue(Grid.RowProperty, rowCount);
MyGrid.Children.Add(imgIcon);
AddToRowList(newContainer);
}
// -------------------- 4 ---------------------
public void RemoveClientGrid(Client c)
{
RowContainer con = RowExists(c);
if (con == null)
return;
if (MyGrid.RowDefinitions.Count < con.rowNumber)
{
RemoveFromRowList(con);
return;
}
Console.WriteLine("Removing row: " + con.rowNumber);
Console.WriteLine("Total rows: " + MyGrid.RowDefinitions.Count);
RowDefinitionCollection defs = MyGrid.RowDefinitions;
foreach (UIElement control in MyGrid.Children)
{
if (Grid.GetRow(control) == con.rowNumber)
{
MyGrid.Children.Remove(control);
}
}
defs.RemoveAt(con.rowNumber);
RemoveFromRowList(con);
}
protected override void OnClosing(CancelEventArgs e)
{
if (debugWindow != null)
debugWindow.Close();
Environment.Exit(Environment.ExitCode);
base.OnClosing(e);
}
private void onServerStartClick(object sender, RoutedEventArgs e)
{
if (ConnectionHandler == null)
{
ConnectionHandler = new ConnectionHandle();
}
else
{
MessageBox.Show("Server Has Already Started!");
}
}
private Client GetRowClient(int row)
{
foreach(RowContainer r in RowContents) {
if (r.rowNumber == row)
return r.client;
}
return null;
}
private void onRefreshMenuClick(object sender, RoutedEventArgs e)
{
MenuItem mi = sender as MenuItem;
if (mi != null)
{
ContextMenu cm = mi.CommandParameter as ContextMenu;
if (cm != null)
{
Grid g = cm.PlacementTarget as Grid;
if (g != null)
{
var p = Mouse.GetPosition(g);
int row = 0;
int col = 0;
double accumulatedHeight = 0.0;
double accumulatedWidth = 0.0;
// calc row mouse was over
foreach (var rowDefinition in g.RowDefinitions)
{
accumulatedHeight += rowDefinition.ActualHeight;
if (accumulatedHeight >= p.Y)
break;
row++;
}
Client c = GetRowClient(row);
if (c != null)
{
ConnectionHandle.SendRequestInformation(c, 1);
ConnectionHandle.SendRequestInformation(c, 4);
}
else
if (debugWindow != null)
debugWindow.LogTextBox.AppendText("Unable to find client!");
}
}
}
}
private void onDisconnectClicked(object sender, RoutedEventArgs e)
{
MenuItem mi = sender as MenuItem;
if (mi != null)
{
ContextMenu cm = mi.CommandParameter as ContextMenu;
if (cm != null)
{
Grid g = cm.PlacementTarget as Grid;
if (g != null)
{
var p = Mouse.GetPosition(g);
int row = 0;
int col = 0;
double accumulatedHeight = 0.0;
double accumulatedWidth = 0.0;
// calc row mouse was over
foreach (var rowDefinition in g.RowDefinitions)
{
accumulatedHeight += rowDefinition.ActualHeight;
if (accumulatedHeight >= p.Y)
break;
row++;
}
Client c = GetRowClient(row);
if (c != null)
{
// ----- RemoveFromClientPool is basically RemoveClientGrid(c) seen above.
ClientHandle.RemoveFromClientPool(c, "Server Requested");
}
else
if (debugWindow != null)
debugWindow.LogTextBox.AppendText("Unable to find client!");
}
}
}
}
}
1) 我将此方法标记为 RemoveFromRowList 只是因为我不确定在尝试删除行时是否所有行都需要向上移动。行号在 RowContainer class 中给出并保存。
2) 几乎和一个问题一样......我不确定到底发生了什么所以我只是插入了一个行号......所以说如果有 5 个客户端并且 wpf 网格上的第 3 个客户端断开连接下一个连接的客户端获得第 3 行?这听起来很傻,请告诉我他们只是被转移了,因为 4 会变成 3 而 5 会变成 4 ...?
3) 这就是它为网格生成新行的方式。它很难看,但它似乎在工作我唯一关心的是第 0 行的编号采用了我的一些默认文本。所以我猜计数会让我从正确的新行开始。因为如果第一个客户端出现,它的计数 = 1(只计算我之前的默认行)。
4) 好吧,我认为这是我的主要问题。删除所有控件和行本身。看起来它现在正在抛出 System.InvalidOperationException。但我也确定我的行编号已关闭...
---- 总体问题:a) 当一行离开时,行号会发生什么变化? (新客户来了,它排在最后一个位置,而那里的所有其他客户都向上移动了?)
b) 如何有效地删除 wpf 上 Grid 中的一行,包括该行中的所有控件?
我不认为我的 RowContainer 有问题 class 它只是 atm 不干净,我可以做所有 get;set;但它显然不会抛出任何真正的错误。
public class RowContainer
{
public byte[] Image { get; set; }
public String state;
public String ip;
public String Os {get; set;}
public String bitacc;
public String idle {get; set;}
public Client client;
public int rowNumber { get; set; }
public RowContainer(Client c)
{
this.ip = c.getClientIp();
this.client = c;
}
public void SetIdleTime(String time)
{
this.idle = time;
}
public void SetState(String st)
{
this.state = st;
}
public void SetBCAccount(String bc){
this.bitacc = bc;
}
public String GetIp()
{
return this.ip;
}
public String GetBitAccount()
{
return this.bitacc;
}
public Client GetClient()
{
return this.client;
}
public String GetIdleTime()
{
return this.idle;
}
public String GetState()
{
return this.GetState();
}
}
我猜你是 WPF 的新手,所以我的第一个建议是腾出一些时间来阅读有关 MVVM 的内容。这是 WPF 的主要优势之一。你可以看看那个问题
MVVM: Tutorial from start to finish?
关于你的问题,网格控件是一种布局控件,请看这里http://www.wpftutorial.net/GridLayout.html
当您想显示项目列表时,最好使用 ItemsControl(例如 ListBox)。
阅读此处:http://www.wpf-tutorial.com/list-controls/itemscontrol/ 这将为您省去维护有效索引和处理行的创建和删除的麻烦。
下面我将附上我的 window 的整个 class(这是 wpf)。我将评论我认为是 issues/concerns/problems 的内容,然后我将在下面按列表顺序解释我的评论。最有帮助的答案将是那些使用代码作为参考来回答列出的问题的人。我会提供mainwindowcs和RowContainerclass(简单管理class)。
这是 gui 的图片...
public partial class MainWindow : Window
{
public static DebugWindow debugWindow;
public static MainWindow mainWindow;
public static Dispatcher mainWindowDispacter;
private Object locker = new Object();
public ConnectionHandle ConnectionHandler;
public RowContainer[] RowContents;
public MainWindow()
{
InitializeComponent();
mainWindow = this;
mainWindowDispacter = this.Dispatcher;
}
public RowContainer RowExists(Client c)
{
if (RowContents == null)
return null;
foreach (RowContainer r in RowContents)
{
if (r.GetClient().getUID().Equals(c.getUID()))
return r;
}
return null;
}
// ----------------1 --------------------
public void RemoveFromRowList(RowContainer r)
{
List<RowContainer> l = new List<RowContainer>();
List<int> usedList = new List<int>();
int deleteRowNumber = r.rowNumber;
foreach (RowContainer rr in RowContents)
{
if (!r.Equals(rr))
{
if (rr.rowNumber > deleteRowNumber)
rr.rowNumber--;
l.Add(rr);
}
}
RowContents = l.ToArray();
}
//----------------------- 2 -------------------
public void AddToRowList(RowContainer r)
{
if (RowContents == null)
{
r.rowNumber = 1;
RowContents = new RowContainer[] { r };
return;
}
List<RowContainer> l = new List<RowContainer>();
List<int> usedList = new List<int>();
foreach (RowContainer rr in RowContents)
{
l.Add(rr);
usedList.Add(rr.rowNumber);
}
Console.WriteLine(usedList.ToString());
int? firstAvailable = Enumerable.Range(1, int.MaxValue)
.Except(usedList)
.FirstOrDefault();
r.rowNumber = (int)firstAvailable;
l.Add(r);
RowContents = l.ToArray();
}
private void onDebugLogClick(object sender, RoutedEventArgs e)
{
if (debugWindow == null)
{
debugWindow = new DebugWindow();
debugWindow.Show();
}
else
{
if (debugWindow.IsVisible)
{
debugWindow.Hide();
}
else
debugWindow.Visibility = Visibility.Visible;
}
}
public BitmapImage ToImage(byte[] array)
{
using (var ms = new System.IO.MemoryStream(array))
{
var image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = ms;
image.EndInit();
return image;
}
}
// type 0 - image, 1 - status, 2 - OS, 3 - Idle, 4 - bitaccount
public void UpdateRowContainer(RowContainer r, int type)
{
switch (type)
{
case 0:
BitmapImage image = ToImage(r.Image);
System.Windows.Controls.Image uiImage = (System.Windows.Controls.Image)MyGrid.Children.Cast<UIElement>().First(e => Grid.GetRow(e) == r.rowNumber & Grid.GetColumn(e) == 0);
if (uiImage == null)
{
}
else
{
uiImage.Source = image;
}
break;
case 2:
Label OsLabel = (System.Windows.Controls.Label)MyGrid.Children.Cast<UIElement>().First(e => Grid.GetRow(e) == r.rowNumber & Grid.GetColumn(e) == 5);
OsLabel.Content = r.Os;
break;
case 3:
Label idleLabel = (System.Windows.Controls.Label)MyGrid.Children.Cast<UIElement>().First(e => Grid.GetRow(e) == r.rowNumber & Grid.GetColumn(e) == 3);
idleLabel.Content = r.idle;
break;
}
}
// --------------------------- 3----------------------
public void CreateClientRowContainer(Client c, byte[] imageBytes)
{
RowContainer newContainer = new RowContainer(c);
BitmapImage image = ToImage(imageBytes);
newContainer.Image = imageBytes;
Label cLabel = new Label();
Label osLabel = new Label();
Label stateLabel = new Label();
Label bitAccountLabel = new Label();
Label idleTimeLabel = new Label();
osLabel.Content = "N/A";
stateLabel.Content = "N/A";
bitAccountLabel.Content = "N/A";
idleTimeLabel.Content = "N/A";
cLabel.Content = c.getClientIp();
cLabel.SetValue(Grid.ColumnProperty, 1);
stateLabel.SetValue(Grid.ColumnProperty, 2);
idleTimeLabel.SetValue(Grid.ColumnProperty, 3);
bitAccountLabel.SetValue(Grid.ColumnProperty, 4);
osLabel.SetValue(Grid.ColumnProperty, 5);
int rowCount = this.MyGrid.RowDefinitions.Count;
this.MyGrid.RowDefinitions.Add(new RowDefinition());
Style style = this.FindResource("LabelTemplate") as Style;
Style style2 = this.FindResource("OSTemplate") as Style;
cLabel.Style = style;
stateLabel.Style = style;
bitAccountLabel.Style = style;
idleTimeLabel.Style = style;
osLabel.Style = style2;
cLabel.SetValue(Grid.RowProperty, rowCount);
bitAccountLabel.SetValue(Grid.RowProperty, rowCount);
stateLabel.SetValue(Grid.RowProperty, rowCount);
idleTimeLabel.SetValue(Grid.RowProperty, rowCount);
osLabel.SetValue(Grid.RowProperty, rowCount);
System.Windows.Controls.Image imgIcon = new System.Windows.Controls.Image();
imgIcon.Height = 150;
imgIcon.HorizontalAlignment = HorizontalAlignment.Center;
imgIcon.VerticalAlignment = VerticalAlignment.Top;
imgIcon.Source = image;
MyGrid.Children.Add(cLabel);
MyGrid.Children.Add(idleTimeLabel);
MyGrid.Children.Add(stateLabel);
MyGrid.Children.Add(bitAccountLabel);
MyGrid.Children.Add(osLabel);
ConnectionHandle.SendRequestInformation(c, 3);
imgIcon.SetValue(Grid.ColumnProperty, 0);
imgIcon.SetValue(Grid.RowProperty, rowCount);
MyGrid.Children.Add(imgIcon);
AddToRowList(newContainer);
}
// -------------------- 4 ---------------------
public void RemoveClientGrid(Client c)
{
RowContainer con = RowExists(c);
if (con == null)
return;
if (MyGrid.RowDefinitions.Count < con.rowNumber)
{
RemoveFromRowList(con);
return;
}
Console.WriteLine("Removing row: " + con.rowNumber);
Console.WriteLine("Total rows: " + MyGrid.RowDefinitions.Count);
RowDefinitionCollection defs = MyGrid.RowDefinitions;
foreach (UIElement control in MyGrid.Children)
{
if (Grid.GetRow(control) == con.rowNumber)
{
MyGrid.Children.Remove(control);
}
}
defs.RemoveAt(con.rowNumber);
RemoveFromRowList(con);
}
protected override void OnClosing(CancelEventArgs e)
{
if (debugWindow != null)
debugWindow.Close();
Environment.Exit(Environment.ExitCode);
base.OnClosing(e);
}
private void onServerStartClick(object sender, RoutedEventArgs e)
{
if (ConnectionHandler == null)
{
ConnectionHandler = new ConnectionHandle();
}
else
{
MessageBox.Show("Server Has Already Started!");
}
}
private Client GetRowClient(int row)
{
foreach(RowContainer r in RowContents) {
if (r.rowNumber == row)
return r.client;
}
return null;
}
private void onRefreshMenuClick(object sender, RoutedEventArgs e)
{
MenuItem mi = sender as MenuItem;
if (mi != null)
{
ContextMenu cm = mi.CommandParameter as ContextMenu;
if (cm != null)
{
Grid g = cm.PlacementTarget as Grid;
if (g != null)
{
var p = Mouse.GetPosition(g);
int row = 0;
int col = 0;
double accumulatedHeight = 0.0;
double accumulatedWidth = 0.0;
// calc row mouse was over
foreach (var rowDefinition in g.RowDefinitions)
{
accumulatedHeight += rowDefinition.ActualHeight;
if (accumulatedHeight >= p.Y)
break;
row++;
}
Client c = GetRowClient(row);
if (c != null)
{
ConnectionHandle.SendRequestInformation(c, 1);
ConnectionHandle.SendRequestInformation(c, 4);
}
else
if (debugWindow != null)
debugWindow.LogTextBox.AppendText("Unable to find client!");
}
}
}
}
private void onDisconnectClicked(object sender, RoutedEventArgs e)
{
MenuItem mi = sender as MenuItem;
if (mi != null)
{
ContextMenu cm = mi.CommandParameter as ContextMenu;
if (cm != null)
{
Grid g = cm.PlacementTarget as Grid;
if (g != null)
{
var p = Mouse.GetPosition(g);
int row = 0;
int col = 0;
double accumulatedHeight = 0.0;
double accumulatedWidth = 0.0;
// calc row mouse was over
foreach (var rowDefinition in g.RowDefinitions)
{
accumulatedHeight += rowDefinition.ActualHeight;
if (accumulatedHeight >= p.Y)
break;
row++;
}
Client c = GetRowClient(row);
if (c != null)
{
// ----- RemoveFromClientPool is basically RemoveClientGrid(c) seen above.
ClientHandle.RemoveFromClientPool(c, "Server Requested");
}
else
if (debugWindow != null)
debugWindow.LogTextBox.AppendText("Unable to find client!");
}
}
}
}
}
1) 我将此方法标记为 RemoveFromRowList 只是因为我不确定在尝试删除行时是否所有行都需要向上移动。行号在 RowContainer class 中给出并保存。
2) 几乎和一个问题一样......我不确定到底发生了什么所以我只是插入了一个行号......所以说如果有 5 个客户端并且 wpf 网格上的第 3 个客户端断开连接下一个连接的客户端获得第 3 行?这听起来很傻,请告诉我他们只是被转移了,因为 4 会变成 3 而 5 会变成 4 ...?
3) 这就是它为网格生成新行的方式。它很难看,但它似乎在工作我唯一关心的是第 0 行的编号采用了我的一些默认文本。所以我猜计数会让我从正确的新行开始。因为如果第一个客户端出现,它的计数 = 1(只计算我之前的默认行)。
4) 好吧,我认为这是我的主要问题。删除所有控件和行本身。看起来它现在正在抛出 System.InvalidOperationException。但我也确定我的行编号已关闭...
---- 总体问题:a) 当一行离开时,行号会发生什么变化? (新客户来了,它排在最后一个位置,而那里的所有其他客户都向上移动了?) b) 如何有效地删除 wpf 上 Grid 中的一行,包括该行中的所有控件?
我不认为我的 RowContainer 有问题 class 它只是 atm 不干净,我可以做所有 get;set;但它显然不会抛出任何真正的错误。
public class RowContainer
{
public byte[] Image { get; set; }
public String state;
public String ip;
public String Os {get; set;}
public String bitacc;
public String idle {get; set;}
public Client client;
public int rowNumber { get; set; }
public RowContainer(Client c)
{
this.ip = c.getClientIp();
this.client = c;
}
public void SetIdleTime(String time)
{
this.idle = time;
}
public void SetState(String st)
{
this.state = st;
}
public void SetBCAccount(String bc){
this.bitacc = bc;
}
public String GetIp()
{
return this.ip;
}
public String GetBitAccount()
{
return this.bitacc;
}
public Client GetClient()
{
return this.client;
}
public String GetIdleTime()
{
return this.idle;
}
public String GetState()
{
return this.GetState();
}
}
我猜你是 WPF 的新手,所以我的第一个建议是腾出一些时间来阅读有关 MVVM 的内容。这是 WPF 的主要优势之一。你可以看看那个问题 MVVM: Tutorial from start to finish?
关于你的问题,网格控件是一种布局控件,请看这里http://www.wpftutorial.net/GridLayout.html
当您想显示项目列表时,最好使用 ItemsControl(例如 ListBox)。 阅读此处:http://www.wpf-tutorial.com/list-controls/itemscontrol/ 这将为您省去维护有效索引和处理行的创建和删除的麻烦。