您好,我想知道如何使用 OpenXML 或其他库对 Word 的页面进行编号(即在页脚添加页码),没关系。
我知道这里怎么加页眉,但是我不知道每个页面,就是在页眉1写文章1,在页眉2写文章2,以此类推……
我的问题是什么?我不知道如何为标签(
贴在产品上的二维码本身)选择一个区域(高度、宽度),并且基于这个区域,从图像中打印出二维码。
现在发生的事情要查找Size和Point是花了很多标签。
编码
private void Button_Click(object sender, RoutedEventArgs e)
{
PrintDocument pd = new PrintDocument();
pd.PrintPage += PrintPage;
pd.Print();
}
private void PrintPage(object sender, PrintPageEventArgs e)
{
Image img = Image.FromFile("rezult.png");
//One
System.Drawing.Size size = new System.Drawing.Size(270, 250);
System.Drawing.Point location = new System.Drawing.Point(70, 170);
Rectangle rectangle = new Rectangle(location, size);
e.Graphics.DrawImage(img, rectangle);
}
有一种方法可以将字节数组转换为字符串。问题是堆中的所有内容都很难阅读,您可以按照上面的屏幕截图格式化排水管。
public static string ByteArrayToString(byte[] ba)
{
return BitConverter.ToString(ba);
}
结果:
02-30-00-64-F1-03-11-21-03-03-07-21-58-00-00-00-00-06-41-00-06-00-00-00-00-00-00-00-00-00-00-00-00-56-24-50-5F-23-57-50-22-56-5A-56-54-62-52-59-54-4F-58-00-00-00-00-00-00-DE-DE-DE-80-80-7D-82-7B-7F-00-00-96-96-3A-39-39-00-00-00-09-0F-0F-0F-F0-0F-0F-F0-F0-F0-45-00-10-51-00-08-01-10-51-00-FF-FF-FF-3F-00-00-50-01-00-FE-47-00-01-00-01-10-50-03-00-00-00-00-00-00-00-00-00-00-00-00-00-00
在 ScrollViewer 中,我显示了包(永远的垃圾邮件),界面冻结并且 CPU 负载过重。
系统日志的输出在哪里:
<ScrollViewer c:AutoScrollBehavior.AutoScroll="True" Background="White" Grid.Row="1" Content="{Binding LogSystem, Mode=OneWay}" Margin="10" />
主窗口视图模型
private string logSystem;
public string LogSystem
{
get { return logSystem; }
set
{
logSystem = value;
OnPropertyChanged("LogSystem");
}
}
#region LogMessage
/// <summary>
/// Очистить журнал, если сообщение не предоставлено или пусто.
/// </summary>
/// <param name="msg"></param>
private void Log(string msg = "")
{
if (!exit)
{
if (msg.Length > 0)
{
LogSystem += string.Format("[ {0} ] {1}{2}", DateTime.Now.ToString("HH:mm"), msg, Environment.NewLine);
}
else
{
logSystem = string.Empty;
}
}
}
private string ErrorMsg(string msg)
{
return string.Format("ERROR: {0}", msg);
}
private string SystemMsg(string msg)
{
return string.Format("SYSTEM: {0}", msg);
}
#endregion
联系
private void Connection(MyClient obj)
{
Log(SystemMsg(string.Format("PTU has connected")));
IpClient = $"{((IPEndPoint)obj.client.Client.RemoteEndPoint).Address}:{((IPEndPoint)obj.client.Client.RemoteEndPoint).Port}";
Send("Create Menu", "02-30-00-80-00-01-11-11-ad-09-01-00-00-00-60-8c-90-02-01-20-05-00-10-80-00-00-00-02-42-00-02-05-dc-00-00-00-11-00-00-12-b2-09-02-00-00-00-60-8c-91-02-01-20-05-00-10-00-00-00-00-02-40-00-01-05-de-00-00-00-11-00-00-b1-b0-00-00-c8-13-02-00-00-00-00-00-00-00-00-11-b2-af-00-00-c8-13-02-00-00-00-00-00-00-00-00-11-b3-b1-00-60-88-10-02-10-00-00-00-00-00-00-00-11-b4-ae-00-60-88-10-02-10-00-00-00-00-00-00-00-11-00-01-00-01-10-49-03");
while (obj.client.Connected && active)
{
try
{
obj.stream.BeginRead(obj.buffer, 0, obj.buffer.Length, new AsyncCallback(Read), obj);
obj.handle.WaitOne();
}
catch (Exception ex)
{
Log(ErrorMsg(ex.Message));
}
}
obj.client.Close();
IpClient = string.Empty;
Log(SystemMsg("PTU has disconnected"));
}
读
private void Read(IAsyncResult result)
{
MyClient obj = (MyClient)result.AsyncState;
int bytes = 0;
if (obj.client.Connected)
{
try
{
bytes = obj.stream.EndRead(result);
}
catch (Exception ex)
{
Log(ErrorMsg(ex.Message));
}
}
if (bytes > 0)
{
obj.data.AppendFormat("{0}", Encoding.UTF8.GetString(obj.buffer, 0, bytes));
try
{
if (obj.stream.DataAvailable)
{
obj.stream.BeginRead(obj.buffer, 0, obj.buffer.Length, new AsyncCallback(Read), obj);
}
else
{
var hexString = BitConverter.ToString(obj.buffer,0,bytes);
var name = getterGataTrain.WhatsIt(hexString.ToString());
if (name != null)
{
Log($"PTU->Train: [{name}] {hexString}");
switch (name)
{ //TRIAL RUN RECORD
case "TRIAL RUN RECORD":
StringBuilder hex0 = new StringBuilder();
hex0.Append("02-30-00-64-F1-03-11-21-03-03-07-24-59-FF-AD-00-");//02-30-00-64-F1-03-11-21-03-03-07
hex0.Append("49-05-D8-0F-C0-2E-16-2E-2E-2E-18-15-16-14-14-16-");
hex0.Append("00-00-00-00-00-00-00-00-00-DB-DB-DB-79-83-7B-7D-");
hex0.Append("7A-83-43-44-96-96-3A-39-6A-01-2E-00-0A-00-00-10-");
hex0.Append("00-00-00-00-00-00-55-00-14-41-00-08-01-10-41-10-");
hex0.Append("FF-0F-E0-3F-FF-FF-50-01-00-FE-47-01-01-01-01-10-");
hex0.Append("50-03-00-00-00-00-00-00-00-00-00-00-00-00-00-00");
Send("TRIAL RUN RECORD", hex0.ToString());
break;
}
}
else Log($"PTU->Train: {hexString}");
obj.data.Clear();
obj.handle.Set();
}
}
catch (Exception ex)
{
obj.data.Clear();
Log(ErrorMsg(ex.Message));
obj.handle.Set();
}
}
else
{
obj.client.Close();
obj.handle.Set();
}
}
发送
private void Send(string message,string hex)
{ Log($"Train->PTU:{hex}");
byte[] Send = Convertors.StringToByteArray(hex);
obj.stream.Write(Send, 0, Send.Length);
}
如何从字符串中写入十六进制,以便它们可以正确转换为字节,以便可以正常读取它们,而不是像我拥有一堆,这就是来自wireshark的字节字符串的样子:
02 30 00 80 00 01 11 11 a.d. 09 01 00 00 00 60 8c 90 02 01 20 05 00 10 80 00 00 00 02 42 00 02 05 dc 01 20 05 00 10 25 0 00 00 0 010 0 0 00 00 0 0 0 0 00 11 00 00 b1 b0 00 00 c8 13 02 00 00 00 00 00 00 00 00 11 b2 af 00 00 c8 0 0 0 0 0 00 00 11 b3 b1 00 60 88 10 02 10 00 00 00 01 b 00 01 ae 00 60 88 10 02 10 00 00 00 00 00 00 00 11 00 01 00 01 10 49 03
我的代码
private void Send(MyClient obj)
{
Log($"Train->PTU:Create Menu");
//byte[] Send = Encoding.UTF8.GetBytes("02-20-00-01-11-00-01-00-00-03-00-00")
byte[] Send = Encoding.Default.GetBytes("02-30-00-80-00-01-11-11-ad-09-01-00-00-00-60-8c-90-02-01-20-05-00-10-80-00-00-00-02-42-00-02-05-dc-00-00-00-11-00-00-12-b2-09-02-00-00-00-60-8c-91-02-01-20-05-00-10-00-00-00-00-02-40-00-01-05-de-00-00-00-11-00-00-b1-b0-00-00-c8-13-02-00-00-00-00-00-00-00-00-11-b2-af-00-00-c8-13-02-00-00-00-00-00-00-00-00-11-b3-b1-00-60-88-10-02-10-00-00-00-00-00-00-00-11-b4-ae-00-60-88-10-02-10-00-00-00-00-00-00-00-11-00-01-00-01-10-49-03");
obj.stream.Write(Send, 0, Send.Length);
}
我需要星星在中心,否则看起来有点悲惨,如何格式化?我只需要一个字符串,这就是我将它传递给服务器的原因。
private void SendTextBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
e.Handled = true;
e.SuppressKeyPress = true;
if (sendTextBox.Text.Length > 0)
{
string msg = sendTextBox.Text;
sendTextBox.Clear();
bool isbanedword = ForbiddenWords.Any(w => w == msg);
if(!isbanedword)
{
Log(string.Format("{0} (You): {1}", obj.username, msg));
if (connected)
{
Send(msg);
}
}
else
{
string stars = new string('*', msg.Length);
msg = $"This word can not write:{stars}";
Log(string.Format("{0} (You): {1}", obj.username, msg));
if (connected)
{
Send(msg);
}
}
}
}
}
如何按我在这里知道的许多字段进行排序我有一个字段UserId的多重过滤器。也就是我有3个文本框会写入UserId,在3个文本框中,会得到3个值,应该进行排序。例如:在 3 个文本框中的值如 1、4、5 应该获取所有这些 UserId 1、UserId 4、UserId 5 的数据。
在我看来,只接收一个过滤器,例如在那些 UserId 10中,需要三个过滤器。
主窗口视图模型
class MainWindowViewModel : ViewModelBase
{
public ObservableCollection<User> Users { get; set; }
public ObservableCollection<Todo> Todos { get; set; }
public ObservableCollection<Post> Posts { get; set; }
public ObservableCollection<Сomment> Сomments { get; set; }
public ObservableCollection<Album> Albums { get; set; }
public ObservableCollection<Photo> Photos { get; set; }
public CollectionView TodosView { get; private set; }
private int? filter;
public int? Fileter
{
get { return filter; }
set
{
filter = value;
Filters();
RaisePropertyChanged("Fileter");
}
}
private int? filter2;
public int? Fileter2
{
get { return filter2; }
set
{
filter2 = value;
RaisePropertyChanged("Fileter2");
}
}
private int? filter3;
public int? Fileter3
{
get { return filter3; }
set
{
filter3 = value;
RaisePropertyChanged("Fileter3");
}
}
private void Filters()
{
TodosView.Filter = (obj) =>
{
if (obj is Todo Todo)
return Fileter == Todo.UserId;
return false;
};
TodosView.Refresh();
}
public MainWindowViewModel()
{
Load();
TodosView = (CollectionView)CollectionViewSource.GetDefaultView(Todos);
}
private void Load()
{
string usersjson = GetFile("https://jsonplaceholder.typicode.com/users");
string todosjson = GetFile("https://jsonplaceholder.typicode.com/todos");
string postsjson = GetFile("https://jsonplaceholder.typicode.com/posts");
string commentsjson = GetFile("https://jsonplaceholder.typicode.com/comments");
string albumsjson = GetFile("https://jsonplaceholder.typicode.com/albums");
string photosjson = GetFile("https://jsonplaceholder.typicode.com/photos");
Users = JsonConvert.DeserializeObject<ObservableCollection<User>>(usersjson);
Todos = JsonConvert.DeserializeObject<ObservableCollection<Todo>>(todosjson);
Posts= JsonConvert.DeserializeObject<ObservableCollection<Post>>(postsjson);
Сomments= JsonConvert.DeserializeObject<ObservableCollection<Сomment>>(commentsjson);
Albums = JsonConvert.DeserializeObject<ObservableCollection<Album>>(albumsjson);
Photos = JsonConvert.DeserializeObject<ObservableCollection<Photo>>(photosjson);
}
private string GetFile(string site)
{
string responseString =string.Empty;
using (var webClient = new WebClient())
{
responseString = webClient.DownloadString(site);
}
return responseString;
}
}
主窗口
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="64*"/>
<RowDefinition Height="597*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<GroupBox Header="Multi-filter id" Margin="5">
<StackPanel Margin="5" Orientation="Horizontal">
<TextBlock Margin="10,0,0,0" Text="Filter 1:" />
<TextBox Text="{Binding Fileter,UpdateSourceTrigger=PropertyChanged}" MinWidth="30" />
<TextBlock Margin="10,0,0,0" Text="Filter 2:" />
<TextBox Text="{Binding Fileter2,UpdateSourceTrigger=PropertyChanged}" MinWidth="30" />
<TextBlock Margin="10,0,0,0" Text="Filter 3:" />
<TextBox Text="{Binding Fileter3,UpdateSourceTrigger=PropertyChanged}" MinWidth="30" />
<Button Margin="10,0,0,0" Content="Reset" MinWidth="50"/>
</StackPanel>
</GroupBox>
<DataGrid Margin="5" Grid.Row="1" IsReadOnly="True" ItemsSource="{Binding TodosView}" />
</Grid>
您需要根据IsValidName()
. 对于绘画,一个转换器是由 RowToBrushConverter
继承自 base one 的转换器 的名称创建的ConverterBase
。在属性 DataGrid.RowStyle
中,我设置了DataGridRow
更改线条颜色的样式。
问题是它仅在滚动DataGrid时部分绘制。
它应该如何工作:如果条件为真IsValidName()
,则涂成白色,否则,则涂成红色。
数据网格.RowStyle
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="ToolTip">
<Setter.Value>
<StackPanel>
<TextBlock Text="{Binding ToolTip}" />
</StackPanel>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="{Binding Converter={StaticResource RowToBrush}}"/>
</Style>
</DataGrid.RowStyle>
转换器基础
abstract class ConverterBase : MarkupExtension, IValueConverter
{
public abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture);
public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
public override object ProvideValue(IServiceProvider serviceProvider) => this;
}
RowToBrush 转换器
class RowToBrushConverter : ConverterBase
{
public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (targetType != typeof(Brush))
{
return null;
}
var FileName = (FileName)value;
return !FileName.IsValidName() ? Brushes.Red : Brushes.White;
}
}
文件名
public class FileName:ModelBase
{
private System.IO.FileInfo Info;
private string Directory;
private string original;
public string Original
{
get { return original; }
set
{
original = value;
OriginalImage = GetBitmapSource(GetIcon());
OnPropertyChanged("Original");
}
}
private BitmapSource originalImage;
public BitmapSource OriginalImage
{
get { return originalImage; }
set
{
originalImage = value;
OnPropertyChanged("OriginalImage");
}
}
private string modified;
public string Modified
{
get { return modified; }
set
{
modified = value;
ModifiedImage = GetBitmapSource(GetIconModified());
OnPropertyChanged("Modified");
}
}
public BitmapSource modifiedImage;
public BitmapSource ModifiedImage
{
get { return modifiedImage; }
set
{
modifiedImage = value;
OnPropertyChanged("ModifiedImage");
}
}
public string toolTip { get; set; }
public string ToolTip
{
get { return toolTip; }
set
{
toolTip = value;
OnPropertyChanged("ToolTip");
}
}
public BitmapSource GetBitmapSource(Bitmap bitmap)
{
BitmapSource bitmapSource = Imaging.CreateBitmapSourceFromHBitmap
(
bitmap.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions()
);
return bitmapSource;
}
//Название каталога не должно заканчиваться\
public FileName(string directory, string original, string modified)
{
Directory = directory.TrimEnd('\\');
Original = original;
Modified = modified;
ToolTip= ParentDirectory() + @"\"+ Original;
}
public FileName(FileName name, bool swap = false)
{
Directory = name.Directory.TrimEnd('\\');
Original = name.Original;
Modified = name.Modified;
if (swap) Swap();
}
public void Reset()
{
Modified = Original;
}
public bool IsValidName()
{
if (string.IsNullOrEmpty(Modified))
{
return false;
}
bool result = Modified.IndexOfAny(Path.GetInvalidFileNameChars()) == -1;
return result;
}
public void Swap()
{
var temp = Original;
Original = Modified;
Modified = temp;
}
public string GetExtension()
{
return Path.GetExtension(Original);
}
public string GetModifiedNameWithoutExtension()
{
return Path.GetFileNameWithoutExtension(Modified);
}
public string ParentDirectory()
{
var parts = Directory.Split('\\');
return parts[parts.Length - 1];
}
public string FullPath()
{
return Directory + "\\" + Original;
}
public string FullPathModified(string newDirectory = null)
{
if (newDirectory != null) return newDirectory + "\\" + Modified;
return Directory + "\\" + Modified;
}
public Bitmap GetIcon()
{
return Common.ShellIcon.GetBitmapIcon(FullPath());
}
public Bitmap GetIconModified()
{
return Common.ShellIcon.GetBitmapIcon(FullPathModified());
}
private void LoadFileInfo()
{
if (Info == null)
Info = new System.IO.FileInfo(this.FullPath());
}
public string CreationDate()
{
LoadFileInfo();
return Info.CreationTime.ToShortDateString() + " " + Info.CreationTime.ToShortTimeString();
}
public string LastWriteDate()
{
LoadFileInfo();
return Info.LastWriteTime.ToShortDateString() + " " + Info.LastWriteTime.ToShortTimeString();
}
//trim file length to fit a unit
private double TrimSize(double length, int n = 0)
{
for (int i = 0; i < n; i++) length /= 1024.0; //divide n times by 1024
return Math.Round(Convert.ToDouble(length), 2); //convert to double and round to 2 decimal places
}
public string ReadableFileSize()
{
LoadFileInfo();
long length = Info.Length;
if (length < Math.Pow(1024, 1)) return length + " B"; //lower than 1kb
if (length < Math.Pow(1024, 2)) return TrimSize(length, 1) + " KB"; //lower than 1mb
if (length < Math.Pow(1024, 3)) return TrimSize(length, 2) + " MB"; //lower than 1gb
if (length < Math.Pow(1024, 4)) return TrimSize(length, 3) + " GB"; //lower than 1tb
return length + " TB"; //return size in tb
}
}
当我创建文件名“”时,仍然有些行没有着色,如果我不滚动着色根本不会发生。
大家好,新年快乐。现在,关于这个问题,我正在尝试从YouTube 这里 github重写(从 winform 到 wpf / mvvm)代码:这里,当Stop()线程从Start()停止 时,会发生错误:System.InvalidOperationException: 'Start may不会被要求完成已完成的任务。
店电脑模型
/// <summary>
/// Моделирование работы магазина касс.
/// </summary>
public class ShopComputerModel
{
Generator Generator = new Generator();
Random rnd = new Random();
List<Task> tasks = new List<Task>();
CancellationTokenSource cancelTokenSource;
CancellationToken token;
/// <summary>
/// Касса
/// </summary>
public List<CashDesk> CashDesks { get; set; } = new List<CashDesk>();
public List<Cart> Carts { get; set; } = new List<Cart>();
public List<Check> Checks { get; set; } = new List<Check>();
/// <summary>
/// Продажы
/// </summary>
public List<Sell> Sell { get; set; } = new List<Sell>();
public Queue<Seller> Sellers { get; set; } = new Queue<Seller>();
public int CustomerSpeed { get; set; } = 100;
public int CashDeskSpeed { get; set; } = 100;
public ShopComputerModel()
{
var sellers = Generator.GetNewSellers(20);
Generator.GetNewProducts(1000);
Generator.GetNewCustomers(100);
cancelTokenSource = new CancellationTokenSource();
token = cancelTokenSource.Token;
foreach (var seller in sellers)
{
Sellers.Enqueue(seller);
}
for(int i = 0; i < 3; i++)
{
CashDesks.Add(new CashDesk(CashDesks.Count, Sellers.Dequeue()));
}
}
public void Start()
{
#region Синхронное выполные
//var customers = Generator.GetNewCustomers(10);
////Заполные козины
//var carts = new Queue<Cart>();
//foreach (var customer in customers)
//{
// var cart = new Cart(customer);
// foreach (var prod in Generator.GetRandomProducts(10, 30))
// {
// cart.Add(prod);
// }
// carts.Enqueue(cart);
//}
//while (carts.Count > 0)
//{
// var cash = CashDesks[rnd.Next(CashDesks.Count - 1)];//случайная касса
// cash.Enqueue(carts.Dequeue());//Будем распределять покупателей по одной из 3 класс.
//}
//while (true)//Обслуживаные в кассе людей
//{
// var cash = CashDesks[rnd.Next(CashDesks.Count - 1)];
// var money = cash.Dequeue();
//}
#endregion
#region Асинхронные выполные
tasks.Add(new Task(() => CreateCarts(10, token)));
tasks.AddRange(CashDesks.Select(c => new Task(() => CashDeskWork(c, token))));
foreach (var task in tasks)
{
task.Start();
}
#endregion
}
public void Stop()
{
cancelTokenSource.Cancel();
Thread.Sleep(1000);
}
private void CashDeskWork(CashDesk cashDesk, CancellationToken token)
{
while (!token.IsCancellationRequested)
{ //Если человек есть в очереде,тогда облужаем его.
if (cashDesk.Count > 0)
{
cashDesk.Dequeue();
Thread.Sleep(CashDeskSpeed);
}
}
}
private void CreateCarts(int customerCounts, CancellationToken token)
{
while (!token.IsCancellationRequested)
{
var customers = Generator.GetNewCustomers(customerCounts);
foreach (var customer in customers)
{
var cart = new Cart(customer);
//Заполненные корзину продуктами.
foreach (var product in Generator.GetRandomProducts(10, 30))
{
cart.Add(product);
}
//Клиент будет выбирать из случайных очередей.
var cash = CashDesks[rnd.Next(CashDesks.Count)];
cash.Enqueue(cart);
}
Thread.Sleep(CustomerSpeed);
}
}
}
发电机
/// <summary>
///Будет создавать виртуальные объекты(для системы сrm).
/// </summary>
public class Generator
{
Random rnd = new Random();
public List<Customer> Customers { get; set; } = new List<Customer>();
public List<Product> Products { get; set; } = new List<Product>();
public List<Seller> Sellers { get; set; } = new List<Seller>();
/// <summary>
/// Генерирование покупателей.
/// </summary>
/// <param name="count"></param>
/// <returns></returns>
public List<Customer> GetNewCustomers(int count)
{
var result = new List<Customer>();
for(int i = 0; i < count; i++)
{
var customer = new Customer()
{
CustomerId = Customers.Count,
Name = GetRandomText(),
Password= GetRandomText()
};
Customers.Add(customer);
result.Add(customer);
}
return result;
}
/// <summary>
///Генерирование продавцов.
/// </summary>
/// <param name="count"></param>
/// <returns></returns>
public List<Seller> GetNewSellers(int count)
{
var result = new List<Seller>();
for (int i = 0; i < count; i++)
{
var seller = new Seller()
{
SellerId = Sellers.Count,
Name = GetRandomText()
};
Sellers.Add(seller);//будем сохранить продавцов
result.Add(seller);//тут будем возвращать продавцов
}
return result;
}
/// <summary>
/// Генерирование товаров.
/// </summary>
/// <param name="count"></param>
/// <returns></returns>
public List<Product> GetNewProducts(int count)
{
var result = new List<Product>();
for (int i = 0; i < count; i++)
{
var product = new Product()
{
ProductId = Products.Count,
Name = GetRandomText(),
Count = rnd.Next(10, 1000),
Price = Convert.ToDecimal(rnd.Next(5, 100000) + rnd.NextDouble())
};
Products.Add(product);
result.Add(product);
}
return result;
}
/// <summary>
/// Полученые товаров какие есть уже
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
/// <returns></returns>
public List<Product> GetRandomProducts(int min, int max)
{
var result = new List<Product>();
var count = rnd.Next(min, max);//будем получать счуйное количество товаров
for(int i = 0; i < count; i++)
{
result.Add(Products[rnd.Next(Products.Count - 1)]);
}
return result;
}
private static string GetRandomText()
{
return Guid.NewGuid().ToString().Substring(0, 5);
}
}
有一个ParseItem函数用于解析产品,例如:Product 1,Product 2。
在这里,作为一个例子,产品 2将被解析。
private async static Task ParseItem(string itemUrl)
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("User-Agent", "C# App");
HttpResponseMessage responce = await client.GetAsync(itemUrl);
string source = default;
if (responce != null && responce.StatusCode == HttpStatusCode.OK)
{
source = await responce.Content.ReadAsStringAsync();
}
HtmlParser domParser = new HtmlParser();
IHtmlDocument document = await domParser.ParseDocumentAsync(source);
string name = document.QuerySelector("[data-qaid|=product_name]")?.InnerHtml;
string price = document.QuerySelector("[data-qaid|=product_price]")?.Text();
string code = document.QuerySelector("[data-qaid|=product-sku]")?.Text();
string characteristics = document.QuerySelector("[data-qaid|=attributes]")?.Text();//Характеристики
string company_name = document.QuerySelector("[data-qaid|=company_name]")?.InnerHtml;
//Не могу получить данные переменные всегда будут == null
string info_by_company = document.QuerySelector("[data-qaid|=info_by_company]")?.InnerHtml;
var company_location = document.QuerySelector("[data-qaid|=company_location]");
var phone = document.QuerySelector("[data-qaid|=phone]");
var site = document.QuerySelector("[data-qaid|=site]");
var schedule_block = document.QuerySelector("[data-qaid|=schedule_block]");
}
static async Task Main()
{
await ParseItem("https://prom.ua/p1203034278-nabor-dlya-uhoda.html");
Console.ReadKey();
}
问题:我尝试解析每个产品,问题总是一样,我无法从图1 的块中获取数据
您需要获取最后的页码进行解析。
分类:
1)当您可以获取最后一页的编号时,就像它在网站上的标签一样 kinoprofi.vip/。
也就是说,如果你从div块中解析所有标签a,你可以得到最后一页的编号。
html代码
<div class="navigation-block">
<div class="navigation">
<span>Назад</span> <span>1</span> <a href="https://kinoprofi.vip/page/2/">2</a> <a href="https://kinoprofi.vip/page/3/">3</a> <a href="https://kinoprofi.vip/page/4/">4</a> <a href="https://kinoprofi.vip/page/5/">5</a> <span class="nav_ext">...</span> <a href="https://kinoprofi.vip/page/1017/">1017</a> <a href="https://kinoprofi.vip/page/2/" class="next">Далее</a>
</div>
2)当您需要点击最后一页的编号时,我们会得到其他页面ekb.zarplata.ru。
在这里,我们只有在按下最后一个,即第 5 页后才能获得下一页的页码,以此类推。
那么如何获得最后一页,我认为单击该站点以搜索最后一页不是一个选项?!我认为没有人需要这样的解析器。
html代码
3)当按钮被按下时,我们得到下一页prom.ua,也不清楚如何获取最后一页。
html代码
<div class="ek-box ek-box_padding_xs"><button data-qaid="load-more-button" type="button" class="ek-button ek-button_theme_yellow ek-button_width_1-1"><div>Показати ще</div></button></div>
我开始阅读有关 Anglesharp 的官方文档,最后一个示例在 JavaScript 和 C# 中以某种奇怪的方式工作。从逻辑上讲,我应该从加载事件中获取文本并从脚本中获取hello,但我只能从 c# 代码中获取它。
编码
using AngleSharp;
using System;
namespace ConsoleApp1
{
class MyClass
{
public async static void EventScriptingExample()
{
//We require a custom configuration
var config = Configuration.Default.WithJs();
//Create a new context for evaluating webpages with the given config
var context = BrowsingContext.New(config);
//This is our sample source, we will trigger the load event
var source = @"<!doctype html>
<html>
<head><title>Event sample</title></head>
<body>
<script>
console.log('Before setting the handler!');
document.addEventListener('load', function() {
console.log('Document loaded!');
});
document.addEventListener('hello', function() {
console.log('hello world from JavaScript!');
});
console.log('After setting the handler!');
</script>
</body>";
var document = await context.OpenAsync(req => req.Content(source));
//HTML should be output in the end
Console.WriteLine(document.DocumentElement.OuterHtml);
//Register Hello event listener from C# (we also have one in JS)
document.AddEventListener("hello", (s, ev) =>
{
Console.WriteLine("hello world from C#!");
});
var e = document.CreateEvent("event");
e.Init("hello", false, false);
document.Dispatch(e);
}
static void Main()
{
EventScriptingExample();
Console.ReadKey();
}
}
}
它应该是:
我能得到什么:
注意:也就是说,事件只能从 c# 代码中执行。
我想不通如何从文章标签中使用正则表达式获取data-file-url属性的值,即获取链接 https://data/image.png。
<article id="post_299290" class="post-preview blacklisted" data-id="299290" data-approver-id="35" data-width="2528" data-height="2924"
data-flags="" data-score="0" data-fav-count="9" data-file-ext="png" data-normalized-source="" data-is-favorited="false"
data-file-url="https://data/image.png" data-uploader-id="39" data-large-file-url="https://data/sample/sample-image.jpg" data-preview-file-url="https://data/preview/image.jpg"/>
我需要做什么:假设用户使用 SaveFileDialog 类选择了保存文件的位置,我如何沿着这条路径生成数据库。
注意:我无法弄清楚为什么程序在生成数据库时挂起。
我的文章数据库生成实体:
public class Article
{
public int Id { set; get; }
public string Title { get; set; }
public string Text { get; set; }
public string Image { get; set;
public Article() { }
public Article(string title, string text, string image)
{
Title = title;
Text = text;
Image = image;
}
}
文章上下文
public class ArticleContext : DbContext
{
public ArticleContext() : base("DBConnect") { }
public DbSet<Article> Articles { get; set; }
public static void Save<T>(List<T> item) where T : class
{
using (var db = new ArticleContext())
{
db.Set<T>().AddRange(item);
db.SaveChanges();//Сохраняем все изменения, сделанные в базовой базе данных.
}
}
}
接收到数据库的 DBConnect 字符串
<connectionStrings>
<add name="DBConnect"
connectionString="data source=(localdb)\MSSQLLocalDB;Initial Catalog=ParserHabr;Integrated Security=True;"
providerName="System.Data.SqlClient"/>
</connectionStrings>
我需要从站点站点保存数据,我需要获取图片、描述、文章标题。
文章标题一切正常
IEnumerable<IElement> items = document.QuerySelectorAll("a").Where(item => item.ClassName != null && item.ClassName.Contains("post__title_link"));
收到图片问题:
var menuPics = document.QuerySelectorAll("img").Where(el => el.ClassName == null).Select(el => el.GetAttribute("src")).ToList();
也就是说,除了需要的图片之外,我得到的不明白是什么。我使用了Video中的解析器,只是为 wpf + mvvm 重新制作了它。
我需要检查OfferModel类的所有属性。
问题是您需要检查:Picture、Descriptions、Param因为它们是集合而不是属性。
例如:如何检查 Descriptions.Text 集合的属性是否为空(即用户输入数据,一切正常,如果不是这样,文本框变为红色,我用 IDataErrorInfo做)并检查集合有元素 Descriptions.Count()>0 然后按钮被禁用。
也就是说,如果集合中的 Descriptions.Count()>0 超过 0 个元素,并且如果元素都是空的空激活按钮。
我用这个例子来检查数据验证。我有集合模型,但我不知道如何检查数据验证。
报价模型
class OfferModel:ChangeProperty,IDataErrorInfo
{
#region Cвойства
string url { get; set; }
public string Url
{
get { return url; }
set
{
url = value;
OnPropertyChanged("Url");
}
}
decimal price { get; set; }
public decimal Price
{
get { return price; }
set
{
price = value;
OnPropertyChanged("Price");
}
}
string currencyId { get; set; }
public string CurrencyId
{
get { return currencyId; }
set
{
currencyId = value;
OnPropertyChanged("CurrencyId");
}
}
int categoryId { get; set; }
public int CategoryId
{
get { return categoryId; }
set
{
categoryId = value;
OnPropertyChanged("CategoryId");
}
}
public ObservableCollection<string> Picture { get; set; } = new ObservableCollection<string>();
string name { get; set; }
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged("Name");
}
}
string vendor { get; set; }
public string Vendor
{
get { return vendor; }
set
{
vendor = value;
OnPropertyChanged("Vendor");
}
}
public ObservableCollection<DescriptionModel> Descriptions { get; set; } = new ObservableCollection<DescriptionModel>();
public ObservableCollection<ParamModel> Param { get; set; } = new ObservableCollection<ParamModel>();
int stock_quantity { get; set; }
public int Stock_quantity
{
get { return stock_quantity; }
set
{
stock_quantity = value;
OnPropertyChanged("Stock_quantity");
}
}
bool аvailable { get; set; }
public bool Available
{
get { return аvailable; }
set
{
аvailable = value;
OnPropertyChanged("Available");
}
}
int id { get; set; }
public int Id
{
get { return id; }
set
{
id = value;
OnPropertyChanged("Id");
}
}
#endregion
#region Проверка свойств
string er { get; set; }
public string Error
{
get { return er; }
}
public string this[string propertyName]
{
get
{
string validationResult = null;
switch (propertyName)
{
case "Name":
validationResult = Validation.Name(Name);
break;
case "Url":
validationResult = Validation.Ui(Url);
break;
case "Price":
validationResult = Validation.Price(Price);
break;
case "Vendor":
validationResult = Validation.Vendor(Vendor);
break;
case "Stock_quantity":
validationResult = Validation.StockQuantity(Stock_quantity);
break;
default:throw new ApplicationException("Неизвестное свойство проверяется модели OfferModel.");
}
return validationResult;
}
}
#endregion
public OfferModel(){}
public OfferModel(string url, decimal price, string currencyId, int categoryId, string name, string vendor, int stock_quantity, bool available, int id)
{
Url = url;
Price = price;
CurrencyId = currencyId;
CategoryId = categoryId;
Name = name;
Vendor = vendor;
Stock_quantity = stock_quantity;
Available = available;
Id = id;
}
}
参数模型
class ParamModel :ChangeProperty,IDataErrorInfo
{
string name { get; set; }
string text { get; set; }
/// <summary>
/// Xарактеристику параметра.
/// </summary>
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged("Name");
}
}
/// <summary>
/// Значение параметра.
/// </summary>
public string Text
{
get { return text; }
set
{
text = value;
OnPropertyChanged("Text");
}
}
public ParamModel() { }
public ParamModel(string name, string text)
{
Name = name;
Text = text;
}
#region Проверка свойств
string er { get; set; }
public string Error
{
get { return er; }
}
public string this[string propertyName]
{
get
{
string validationResult = null;
switch (propertyName)
{
case "Name":
validationResult = Validation.NameParam(Name);
break;
case "Text":
validationResult = Validation.TextParam(Text);
break;
default:throw new ApplicationException("Неизвестное свойство проверяется модели ParamModel.");
}
return validationResult;
}
}
#endregion
}
描述型号
class DescriptionModel:ChangeProperty,IDataErrorInfo
{
private string text { get; set; }
public string Text
{
get { return text; }
set
{
text = value;
OnPropertyChanged(nameof(Text));
}
}
public DescriptionModel() { }
public DescriptionModel(string text)
{
Text = text;
}
#region Проверка свойств
string er { get; set; }
public string Error
{
get { return er; }
}
public string this[string propertyName]
{
get
{
string validationResult = null;
switch (propertyName)
{
case "Text":
validationResult = Validation.Text(Text);
break;
default: throw new ApplicationException("Неизвестное свойство проверяется модели DescriptionModel.");
}
return validationResult;
}
}
#endregion
}
添加产品时如何检查集合的 AddProductViewModel属性:Picture.CollectionChanged - 添加到集合时,item.PropertyChanged - 属性更改时。
这在触发 CollectionChanged 事件时很好(也就是说,当添加到集合时,如果通过引用将报价传递给用于测量产品的构造函数,则 CollectionChanged 事件将不起作用)。
还有另一种实现验证的方法吗?
readonly OfferModel offer;
/// <summary>
/// Хранения валлидность свойств.
/// </summary>
private Dictionary<string, bool> validProperties;
/// <summary>
/// Включить кнопку если все свойства валлидни.
/// </summary>
private bool allPropertiesValid = false;
public bool AllPropertiesValid
{
get { return allPropertiesValid; }
set
{
if (allPropertiesValid != value)
{
allPropertiesValid = value;
OnPropertyChanged("AllPropertiesValid");
}
}
}
#region Валидации данных
validProperties = new Dictionary<string, bool>();//нужен для того чтобы включить кнопку добавленные если все данные будут коректные.
validProperties.Add("Name", false);
validProperties.Add("Url", false);
validProperties.Add("Price", false);
validProperties.Add("Vendor", false);
validProperties.Add("Stock_quantity", false);
validProperties.Add("Picture", false);
validProperties.Add("Descriptions", false);
validProperties.Add("Param", false);
//Проверки на валидность ввода Picture Descriptions Param.
Picture.CollectionChanged += (s, e) =>
{
validProperties["Picture"] = Picture.Count() > 0 ? true : false;
ValidateProperties();
};
Descriptions.CollectionChanged += (s, e) =>
{
bool isEmpty = false;
if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach (DescriptionModel item in e.NewItems)//Добавление новые элементы
{
isEmpty = Validation.TextBool(item.Text) ? false : true;
item.PropertyChanged += (sender, argument) => //Проходимся по свойствам модели.
{
int i = 0;
foreach (var des in Descriptions)
{
if (Validation.TextBool(des.Text))
{
i++;
}
}
validProperties["Descriptions"] = (i == 0) ? true : false;
isEmpty = (i == 0) ? true : false;
ValidateProperties();
};
}
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
int i = 0;
foreach (var des in Descriptions)
{
if (Validation.TextBool(des.Text))
{
i++;
}
}
isEmpty = (i == 0) ? true : false;
}
validProperties["Descriptions"] = (Descriptions.Count > 0 && isEmpty != false) ? true : false;
ValidateProperties();
};
Param.CollectionChanged += (s, e) =>
{
bool isEmpty = false;
if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach (ParamModel item in e.NewItems)//Добавление новые элементы
{
var name = Validation.NameBoolParam(item.Name);
var text = Validation.TextBoolParam(item.Text);
validProperties["Param"] = (name && text) ? false: true;
item.PropertyChanged += (sender, argument) => //Проходимся по свойствам модели.
{
int nameisvalid = 0;
int textisvalid = 0;
foreach (var par in Param)//Ищем неправильно заполнены параметры.
{
if (Validation.NameBoolParam(par.Name)) nameisvalid++;
if (Validation.TextBoolParam(par.Text)) textisvalid++;
}
validProperties["Param"] = (nameisvalid == 0 && textisvalid == 0) ? true : false;
isEmpty = (nameisvalid == 0 && textisvalid == 0) ? true : false;
ValidateProperties();
};
}
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
int nameisvalid = 0;
int textisvalid = 0;
foreach (var par in Param)
{
if (Validation.NameBoolParam(par.Name)) nameisvalid++;
if (Validation.TextBoolParam(par.Text)) textisvalid++;
}
isEmpty = (nameisvalid == 0 && textisvalid == 0) ? true : false;
}
validProperties["Param"] = (Param.Count > 0 && isEmpty != false) ? true : false;
ValidateProperties();
};
#endregion
#region Реализация IDataErrorInfo
public string Error
{
get { return (offer as IDataErrorInfo).Error; }
}
public string this[string propertyName]
{
get
{ if(offer != null)
{
string error = (offer as IDataErrorInfo)[propertyName];
validProperties[propertyName] = string.IsNullOrEmpty(error) ? true : false;
ValidateProperties();
CommandManager.InvalidateRequerySuggested();
return error;
}
return null;
}
}
private void ValidateProperties()
{
foreach (bool isValid in validProperties.Values)
{
if (!isValid)
{
AllPropertiesValid = false;
return;
}
}
AllPropertiesValid = true;
}
#endregion
问题是转换器不想在ResourceDictionary(ListBox.xaml)中工作,如果它包含在App.xaml中,只有当你直接将它连接到ListBox.xaml <converters:BoolToStringConverter x:Key="BoolToString" />一切都会变好。
错误:异常:找不到名为“BoolToString”的资源。资源名称区分大小写。
我真正想要得到的是:是否有可能以某种方式从App.xaml到ListBox.xaml获得转换器,这 不是仅在ListBox.xaml中使用的选项。
列表框.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:PriceCreator.Services.Converters"
>
<converters:BoolToStringConverter x:Key="BoolToString" />
<ControlTemplate x:Key="VideoListItems" TargetType="ListBoxItem">
<Grid>
<Border
Name="brd"
Margin="10,2"
Background="{StaticResource MediumBrush}"
CornerRadius="2">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="25*"/>
<RowDefinition Height="22*"/>
<RowDefinition Height="26*"/>
<RowDefinition Height="818*"/>
</Grid.RowDefinitions>
<TextBlock x:Name="Name" FontWeight="Bold" Foreground="Gray" Style="{StaticResource BaseText}" FontSize="18"
Margin="5" TextTrimming="CharacterEllipsis" Text="{Binding Name,StringFormat=Имя товара:{0}}" TextAlignment="Center" VerticalAlignment="Center"/>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="142*"/>
<ColumnDefinition Width="38*"/>
<ColumnDefinition Width="229*"/>
<ColumnDefinition Width="365*"/>
</Grid.ColumnDefinitions>
<TextBlock Margin="2" x:Name="Price" Grid.Column="0" Text="{Binding Price,StringFormat=Цена:{0}}" FontWeight="Bold" Foreground="Gray" Style="{StaticResource BaseText}" FontSize="18" VerticalAlignment="Center" HorizontalAlignment="Right" />
<TextBlock Margin="2" x:Name="CurrencyId" Grid.Column="1" Text="{Binding CurrencyId}" FontWeight="Bold" Foreground="Gray" Style="{StaticResource BaseText}" FontSize="18" VerticalAlignment="Center" />
<TextBlock FontWeight="Bold" Foreground="Gray" Style="{StaticResource BaseText}" Margin="2" x:Name="Stock_quantity" Grid.Column="2" Text="{Binding Stock_quantity,StringFormat=Количество товаров:{0}}" FontSize="18" VerticalAlignment="Center" />
<TextBlock TextTrimming="CharacterEllipsis" FontWeight="Bold" Foreground="Gray" Style="{StaticResource BaseText}" Margin="2" x:Name="Vendor" Grid.Column="3" Text="{Binding Vendor,StringFormat=Производитель товара:{0}}" FontSize="18" VerticalAlignment="Center"/>
</Grid>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="251*"/>
<ColumnDefinition Width="523*"/>
</Grid.ColumnDefinitions>
<TextBlock Style="{StaticResource BaseText}" Margin="2" Text="{Binding Available,StringFormat=Есть товар в наличии:{0},Converter={StaticResource BoolToString}}" FontSize="18" FontWeight="Bold" Foreground="Gray" />
</Grid>
</Grid>
</Border>
<!--<Polygon
Name="triangle"
Margin="2"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Fill="{Binding ElementName=brd, Path=Background}"
Points="0,0 20,15, 0,30"
Visibility="Hidden" />-->
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="brd" Property="Background" Value="{StaticResource BrushBlue}" />
<!--<Setter TargetName="triangle" Property="Visibility" Value="Visible" />-->
<Setter TargetName="Name" Property="Foreground" Value="White" />
<Setter TargetName="Price" Property="Foreground" Value="White" />
<Setter TargetName="CurrencyId" Property="Foreground" Value="White" />
<Setter TargetName="Vendor" Property="Foreground" Value="White" />
<Setter TargetName="Stock_quantity" Property="Foreground" Value="White" />
<!--<Setter TargetName="Id" Property="Foreground" Value="White" />-->
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="brd" Property="Background" Value="{StaticResource BrushBlue}" />
<Setter TargetName="Name" Property="Foreground" Value="White" />
<Setter TargetName="Price" Property="Foreground" Value="White" />
<Setter TargetName="CurrencyId" Property="Foreground" Value="White" />
<Setter TargetName="Vendor" Property="Foreground" Value="White" />
<Setter TargetName="Stock_quantity" Property="Foreground" Value="White" />
<!--<Setter TargetName="Id" Property="Foreground" Value="White" />-->
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ResourceDictionary>
应用程序.xaml
<Application x:Class="PriceCreator.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:PriceCreator.Services.Converters"
StartupUri="Views\PriceCeatorView.xaml">
<Application.Resources>
<!--Подключение ресурсов-->
<ResourceDictionary >
<!--Подключение конвертеров-->
<converters:StringTointConverter x:Key="StringToint" />
<converters:IntToVisibilityConverter x:Key="IntToVisibility" />
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles\Colors.xaml"/>
<ResourceDictionary Source="Styles\Fonts.xaml"/>
<!--<ResourceDictionary Source="Styles\Icons.xaml" />-->
<ResourceDictionary Source="Styles\ScrollViewer.xaml" />
<ResourceDictionary Source="Styles\Texts.xaml" />
<ResourceDictionary Source="Styles\Buttons.xaml" />
<!--<ResourceDictionary Source="Styles\RadioButton.xaml" />-->
<!--<ResourceDictionary Source="Styles\ContentControls.xaml" />
<ResourceDictionary Source="Styles\UserControl.xaml" />-->
<ResourceDictionary Source="Styles\ListBox.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
有一个正则表达式^\D?(\d{3})\D?\D?(\d{3})\D?(\d{4})$表示: 库存字段中的项目必须是以列表形式输入,以逗号分隔;预计这些元素将是符合命名法的零件编号;
我不明白与^\D?(\d{3})\D?\D?(\d{3})\D?(\d{4})$模式匹配的字符串应该是什么。我使用该站点进行测试:Regular snip test。
我从哪里获得本文的模板:将复杂的业务规则应用于 WPF 中的数据输入
本文的问题是代码没有源代码(我点击链接,它不起作用),您必须手动完成所有操作,有时此代码没有完全完成。